From 15c91131d92ab99bb49e11882945c5b27b9fb073 Mon Sep 17 00:00:00 2001 From: Nathaniel Woods <nwoods@cimpress.com> Date: Tue, 4 Mar 2025 16:33:21 -0500 Subject: [PATCH 01/42] Added `Clone` implementation for `ChunkBy` --- alloctests/tests/slice.rs | 13 +++++++++++++ core/src/slice/iter.rs | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/alloctests/tests/slice.rs b/alloctests/tests/slice.rs index 2516563187f2d..1e15d54d979a2 100644 --- a/alloctests/tests/slice.rs +++ b/alloctests/tests/slice.rs @@ -1636,6 +1636,19 @@ fn test_chunk_by() { assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), None); + + let mut iter = slice.chunk_by(|a, b| a == b); + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + let mut iter_clone = iter.clone(); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[0][..])); + assert_eq!(iter.next(), None); + assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter_clone.next(), Some(&[1][..])); + assert_eq!(iter_clone.next(), Some(&[0][..])); + assert_eq!(iter_clone.next(), None); } #[test] diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index a687ed7129dc8..bf48068b25457 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -3372,6 +3372,13 @@ where #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by", since = "1.77.0")] +impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { + fn clone(&self) -> Self { + Self { slice: self.slice, predicate: self.predicate.clone() } + } +} + #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 63b6269050859185c529af9f6c903d323953ddeb Mon Sep 17 00:00:00 2001 From: Nathaniel Woods <nwoods@cimpress.com> Date: Thu, 6 Mar 2025 12:33:01 -0500 Subject: [PATCH 02/42] Changing #[stable] tag --- core/src/slice/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/slice/iter.rs b/core/src/slice/iter.rs index bf48068b25457..8cbc6d4832eb8 100644 --- a/core/src/slice/iter.rs +++ b/core/src/slice/iter.rs @@ -3372,7 +3372,7 @@ where #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} -#[stable(feature = "slice_group_by", since = "1.77.0")] +#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")] impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { fn clone(&self) -> Self { Self { slice: self.slice, predicate: self.predicate.clone() } From 18c317fa527a333bbede94257a75c0cc3d7d25ca Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Tue, 3 Jun 2025 00:22:10 -0500 Subject: [PATCH 03/42] Update ABI compatibility docs about null-pointer-optimized enums. Add that the enum must be `#[repr(Rust)]` and not `#[repr(packed)]` or `#[repr(align)]` in order to be ABI-compatible with its null-pointer-optimized field. --- core/src/primitive_docs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/primitive_docs.rs b/core/src/primitive_docs.rs index 10b11613f90fa..9a06e43093edb 100644 --- a/core/src/primitive_docs.rs +++ b/core/src/primitive_docs.rs @@ -1833,6 +1833,8 @@ mod prim_ref {} /// - If `T` is guaranteed to be subject to the [null pointer /// optimization](option/index.html#representation), and `E` is an enum satisfying the following /// requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like". +/// - The enum `E` uses the [`Rust` representation], and is not modified by the `align` or +/// `packed` representation modifiers. /// - The enum `E` has exactly two variants. /// - One variant has exactly one field, of type `T`. /// - All fields of the other variant are zero-sized with 1-byte alignment. @@ -1906,6 +1908,7 @@ mod prim_ref {} /// [`Pointer`]: fmt::Pointer /// [`UnwindSafe`]: panic::UnwindSafe /// [`RefUnwindSafe`]: panic::RefUnwindSafe +/// [`Rust` representation]: <https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation> /// /// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because /// these traits are specially known to the compiler. From da05950c50c1848cab832dc4d2f6921184bb58c6 Mon Sep 17 00:00:00 2001 From: Jeremy Smart <jeremy3141592@gmail.com> Date: Wed, 4 Jun 2025 18:15:12 -0400 Subject: [PATCH 04/42] add Vec::peek_mut --- alloc/src/vec/mod.rs | 35 +++++++++++++++++++++++++ alloc/src/vec/peek_mut.rs | 55 +++++++++++++++++++++++++++++++++++++++ alloctests/lib.rs | 1 + alloctests/tests/vec.rs | 11 ++++++++ 4 files changed, 102 insertions(+) create mode 100644 alloc/src/vec/peek_mut.rs diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index ce7321544b6b9..8763ce674be89 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -109,6 +109,11 @@ mod in_place_collect; mod partial_eq; +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub use self::peek_mut::PeekMut; + +mod peek_mut; + #[cfg(not(no_global_oom_handling))] use self::spec_from_elem::SpecFromElem; @@ -729,6 +734,36 @@ impl<T> Vec<T> { pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } + + /// Returns a mutable reference to the greatest item in the binary heap, or + /// `None` if it is empty. + /// + /// Note: If the `PeekMut` value is leaked, some heap elements might get + /// leaked along with it, but the remaining elements will remain a valid + /// heap. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut vec = Vec::new(); + /// assert!(vec.peek_mut().is_none()); + /// + /// vec.push(1); + /// vec.push(5); + /// vec.push(2); + /// assert_eq!(vec.last(), Some(&2)); + /// if let Some(mut val) = vec.peek_mut() { + /// *val = 0; + /// } + /// assert_eq!(vec.last(), Some(&0)); + /// ``` + #[inline] + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { + PeekMut::new(self) + } } impl<T, A: Allocator> Vec<T, A> { diff --git a/alloc/src/vec/peek_mut.rs b/alloc/src/vec/peek_mut.rs new file mode 100644 index 0000000000000..c0dd941ed3933 --- /dev/null +++ b/alloc/src/vec/peek_mut.rs @@ -0,0 +1,55 @@ +use core::ops::{Deref, DerefMut}; + +use super::Vec; +use crate::fmt; + +/// Structure wrapping a mutable reference to the last item in a +/// `Vec`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See +/// its documentation for more. +/// +/// [`peek_mut`]: Vec::peek_mut +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub struct PeekMut<'a, T> { + vec: &'a mut Vec<T>, +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PeekMut").field(self.deref()).finish() + } +} + +impl<'a, T> PeekMut<'a, T> { + pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> { + if vec.is_empty() { None } else { Some(Self { vec }) } + } + + /// Removes the peeked value from the vector and returns it. + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn pop(self) -> T { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.pop().unwrap_unchecked() } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> Deref for PeekMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked(self.vec.len() - 1) } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> DerefMut for PeekMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + let idx = self.vec.len() - 1; + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked_mut(idx) } + } +} diff --git a/alloctests/lib.rs b/alloctests/lib.rs index 56e60ed4c8448..232cf06fff9b6 100644 --- a/alloctests/lib.rs +++ b/alloctests/lib.rs @@ -42,6 +42,7 @@ #![feature(trusted_random_access)] #![feature(try_reserve_kind)] #![feature(try_trait_v2)] +#![feature(vec_peek_mut)] // tidy-alphabetical-end // // Language features: diff --git a/alloctests/tests/vec.rs b/alloctests/tests/vec.rs index f430d979fa848..0de9da3756180 100644 --- a/alloctests/tests/vec.rs +++ b/alloctests/tests/vec.rs @@ -2698,6 +2698,17 @@ fn test_pop_if_mutates() { assert_eq!(v, [2]); } +#[test] +fn test_peek_mut() { + let mut vec = Vec::new(); + assert!(vec.peek_mut().is_none()); + vec.push(1); + vec.push(2); + assert_eq!(vec.peek_mut(), Some(2)); + *vec.peek_mut() = 0; + assert_eq!(vec.peek_mut(), Some(0)); +} + /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments /// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but /// `vec.insert(usize::MAX, val)` once slipped by! From c6bfd759140235c0f6aa01df7c6d74f1ad63af3a Mon Sep 17 00:00:00 2001 From: Jeremy Smart <jeremy3141592@gmail.com> Date: Fri, 6 Jun 2025 13:07:24 -0400 Subject: [PATCH 05/42] fix tests --- alloc/src/vec/mod.rs | 1 + alloctests/lib.rs | 1 - alloctests/tests/lib.rs | 1 + alloctests/tests/vec.rs | 10 +++++++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 8763ce674be89..96d082aba223d 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -747,6 +747,7 @@ impl<T> Vec<T> { /// Basic usage: /// /// ``` + /// #![feature(vec_peek_mut)] /// let mut vec = Vec::new(); /// assert!(vec.peek_mut().is_none()); /// diff --git a/alloctests/lib.rs b/alloctests/lib.rs index 232cf06fff9b6..56e60ed4c8448 100644 --- a/alloctests/lib.rs +++ b/alloctests/lib.rs @@ -42,7 +42,6 @@ #![feature(trusted_random_access)] #![feature(try_reserve_kind)] #![feature(try_trait_v2)] -#![feature(vec_peek_mut)] // tidy-alphabetical-end // // Language features: diff --git a/alloctests/tests/lib.rs b/alloctests/tests/lib.rs index 38309585fad61..a41162ecd51a0 100644 --- a/alloctests/tests/lib.rs +++ b/alloctests/tests/lib.rs @@ -40,6 +40,7 @@ #![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] +#![feature(vec_peek_mut)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/alloctests/tests/vec.rs b/alloctests/tests/vec.rs index 0de9da3756180..adbd4ccb8972a 100644 --- a/alloctests/tests/vec.rs +++ b/alloctests/tests/vec.rs @@ -2704,9 +2704,13 @@ fn test_peek_mut() { assert!(vec.peek_mut().is_none()); vec.push(1); vec.push(2); - assert_eq!(vec.peek_mut(), Some(2)); - *vec.peek_mut() = 0; - assert_eq!(vec.peek_mut(), Some(0)); + if let Some(mut p) = vec.peek_mut() { + assert_eq!(*p, 2); + *p = 0; + assert_eq!(*p, 0); + } else { + unreachable!() + } } /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments From 78367f40818e17e44436141c5a2624874aed066e Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Mon, 9 Jun 2025 14:17:28 +0200 Subject: [PATCH 06/42] float tests: use assert_biteq in more places --- coretests/tests/floats/f128.rs | 2 + coretests/tests/floats/f16.rs | 2 + coretests/tests/floats/f32.rs | 2 + coretests/tests/floats/f64.rs | 2 + coretests/tests/floats/mod.rs | 431 +++++++++++++++++---------------- 5 files changed, 224 insertions(+), 215 deletions(-) diff --git a/coretests/tests/floats/f128.rs b/coretests/tests/floats/f128.rs index 01770f119df10..ffa05715b2d53 100644 --- a/coretests/tests/floats/f128.rs +++ b/coretests/tests/floats/f128.rs @@ -5,6 +5,8 @@ use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; use std::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + // Note these tolerances make sense around zero, but not for more extreme exponents. /// Default tolerances. Works for values that should be near precise but not exact. Roughly diff --git a/coretests/tests/floats/f16.rs b/coretests/tests/floats/f16.rs index 4797573f7d0dd..7e8ce99dbe081 100644 --- a/coretests/tests/floats/f16.rs +++ b/coretests/tests/floats/f16.rs @@ -4,6 +4,8 @@ use std::f16::consts; use std::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Tolerance for results on the order of 10.0e-2 #[allow(unused)] const TOL_N2: f16 = 0.0001; diff --git a/coretests/tests/floats/f32.rs b/coretests/tests/floats/f32.rs index 4e6509ead2ba8..460aecaac6470 100644 --- a/coretests/tests/floats/f32.rs +++ b/coretests/tests/floats/f32.rs @@ -2,6 +2,8 @@ use core::f32; use core::f32::consts; use core::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Smallest number const TINY_BITS: u32 = 0x1; diff --git a/coretests/tests/floats/f64.rs b/coretests/tests/floats/f64.rs index 74202a3740916..1dfce22c14afe 100644 --- a/coretests/tests/floats/f64.rs +++ b/coretests/tests/floats/f64.rs @@ -2,6 +2,8 @@ use core::f64; use core::f64::consts; use core::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Smallest number const TINY_BITS: u64 = 0x1; diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index f9b6c85f87105..a2b0d6caf13e9 100644 --- a/coretests/tests/floats/mod.rs +++ b/coretests/tests/floats/mod.rs @@ -2,7 +2,7 @@ use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; /// Verify that floats are within a tolerance of each other, 1.0e-6 by default. -macro_rules! assert_approx_eq { +macro_rules! assert_approx_eq_ { ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); @@ -14,10 +14,11 @@ macro_rules! assert_approx_eq { ); }}; } +pub(crate) use assert_approx_eq_ as assert_approx_eq; /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq { +macro_rules! assert_biteq_ { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ let l = $left; let r = $right; @@ -41,17 +42,19 @@ macro_rules! assert_biteq { if !l.is_nan() && !r.is_nan() { // Also check that standard equality holds, since most tests use `assert_biteq` rather // than `assert_eq`. - assert_eq!(l, r) + assert_eq!(l, r); } }}; ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq!(@inner $left, $right, "\n", $($tt)*) + assert_biteq_!(@inner $left, $right, "\n", $($tt)*) }; ($left:expr, $right:expr $(,)?) => { - assert_biteq!(@inner $left, $right, "", "") + assert_biteq_!(@inner $left, $right, "", "") }; } +pub(crate) use assert_biteq_ as assert_biteq; +#[allow(unused)] mod const_asserts { // Shadow some assert implementations that would otherwise not compile in a const-context. // Every macro added here also needs to be added in the `float_test!` macro below. @@ -63,8 +66,43 @@ mod const_asserts { std::assert!($left == $right, $($arg)+) }; } - pub(crate) use assert_eq; + + macro_rules! assert_biteq { + (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ + let l = $left; + let r = $right; + + // Hack to coerce left and right to the same type + let mut _eq_ty = l; + _eq_ty = r; + + assert!(l.to_bits() == r.to_bits()); + + if !l.is_nan() && !r.is_nan() { + // Also check that standard equality holds, since most tests use `assert_biteq` rather + // than `assert_eq`. + assert!(l == r); + } + }}; + ($left:expr, $right:expr , $($tt:tt)*) => { + assert_biteq!(@inner $left, $right, "\n", $($tt)*) + }; + ($left:expr, $right:expr $(,)?) => { + assert_biteq!(@inner $left, $right, "", "") + }; + } + pub(crate) use assert_biteq; + + macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!(diff <= $lim); + }}; + } + pub(crate) use assert_approx_eq; } /// Generate float tests for all our float types, for compile-time and run-time behavior. @@ -101,6 +139,8 @@ macro_rules! float_test { test<$fty:ident> $test:block ) => { mod $name { + use super::*; + #[test] $( $( #[$f16_meta] )+ )? fn test_f16() { @@ -131,7 +171,8 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { - use $crate::floats::const_asserts::assert_eq; + #[allow(unused)] + use $crate::floats::const_asserts::{assert_eq, assert_biteq, assert_approx_eq}; #[test] $( $( #[$f16_const_meta] )+ )? @@ -196,29 +237,25 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).min(0.0), 0.0); - assert!((0.0 as Float).min(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).min(-0.0), -0.0); - assert!((-0.0 as Float).min(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).min(9.0), 9.0); - assert_eq!((-9.0 as Float).min(0.0), -9.0); - assert_eq!((0.0 as Float).min(9.0), 0.0); - assert!((0.0 as Float).min(9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).min(9.0), -0.0); - assert!((-0.0 as Float).min(9.0).is_sign_negative()); - assert_eq!((-0.0 as Float).min(-9.0), -9.0); - assert_eq!(Float::INFINITY.min(9.0), 9.0); - assert_eq!((9.0 as Float).min(Float::INFINITY), 9.0); - assert_eq!(Float::INFINITY.min(-9.0), -9.0); - assert_eq!((-9.0 as Float).min(Float::INFINITY), -9.0); - assert_eq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); - assert_eq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); - assert_eq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NAN.min(9.0), 9.0); - assert_eq!(Float::NAN.min(-9.0), -9.0); - assert_eq!((9.0 as Float).min(Float::NAN), 9.0); - assert_eq!((-9.0 as Float).min(Float::NAN), -9.0); + assert_biteq!((0.0 as Float).min(0.0), 0.0); + assert_biteq!((-0.0 as Float).min(-0.0), -0.0); + assert_biteq!((9.0 as Float).min(9.0), 9.0); + assert_biteq!((-9.0 as Float).min(0.0), -9.0); + assert_biteq!((0.0 as Float).min(9.0), 0.0); + assert_biteq!((-0.0 as Float).min(9.0), -0.0); + assert_biteq!((-0.0 as Float).min(-9.0), -9.0); + assert_biteq!(Float::INFINITY.min(9.0), 9.0); + assert_biteq!((9.0 as Float).min(Float::INFINITY), 9.0); + assert_biteq!(Float::INFINITY.min(-9.0), -9.0); + assert_biteq!((-9.0 as Float).min(Float::INFINITY), -9.0); + assert_biteq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); + assert_biteq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); + assert_biteq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NAN.min(9.0), 9.0); + assert_biteq!(Float::NAN.min(-9.0), -9.0); + assert_biteq!((9.0 as Float).min(Float::NAN), 9.0); + assert_biteq!((-9.0 as Float).min(Float::NAN), -9.0); assert!(Float::NAN.min(Float::NAN).is_nan()); } } @@ -230,32 +267,26 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).max(0.0), 0.0); - assert!((0.0 as Float).max(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).max(-0.0), -0.0); - assert!((-0.0 as Float).max(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).max(9.0), 9.0); - assert_eq!((-9.0 as Float).max(0.0), 0.0); - assert!((-9.0 as Float).max(0.0).is_sign_positive()); - assert_eq!((-9.0 as Float).max(-0.0), -0.0); - assert!((-9.0 as Float).max(-0.0).is_sign_negative()); - assert_eq!((0.0 as Float).max(9.0), 9.0); - assert_eq!((0.0 as Float).max(-9.0), 0.0); - assert!((0.0 as Float).max(-9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).max(-9.0), -0.0); - assert!((-0.0 as Float).max(-9.0).is_sign_negative()); - assert_eq!(Float::INFINITY.max(9.0), Float::INFINITY); - assert_eq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::INFINITY.max(-9.0), Float::INFINITY); - assert_eq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.max(9.0), 9.0); - assert_eq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); - assert_eq!(Float::NEG_INFINITY.max(-9.0), -9.0); - assert_eq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); - assert_eq!(Float::NAN.max(9.0), 9.0); - assert_eq!(Float::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as Float).max(Float::NAN), 9.0); - assert_eq!((-9.0 as Float).max(Float::NAN), -9.0); + assert_biteq!((0.0 as Float).max(0.0), 0.0); + assert_biteq!((-0.0 as Float).max(-0.0), -0.0); + assert_biteq!((9.0 as Float).max(9.0), 9.0); + assert_biteq!((-9.0 as Float).max(0.0), 0.0); + assert_biteq!((-9.0 as Float).max(-0.0), -0.0); + assert_biteq!((0.0 as Float).max(9.0), 9.0); + assert_biteq!((0.0 as Float).max(-9.0), 0.0); + assert_biteq!((-0.0 as Float).max(-9.0), -0.0); + assert_biteq!(Float::INFINITY.max(9.0), Float::INFINITY); + assert_biteq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::INFINITY.max(-9.0), Float::INFINITY); + assert_biteq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.max(9.0), 9.0); + assert_biteq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); + assert_biteq!(Float::NEG_INFINITY.max(-9.0), -9.0); + assert_biteq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); + assert_biteq!(Float::NAN.max(9.0), 9.0); + assert_biteq!(Float::NAN.max(-9.0), -9.0); + assert_biteq!((9.0 as Float).max(Float::NAN), 9.0); + assert_biteq!((-9.0 as Float).max(Float::NAN), -9.0); assert!(Float::NAN.max(Float::NAN).is_nan()); } } @@ -267,27 +298,22 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).minimum(0.0), 0.0); - assert!((0.0 as Float).minimum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).minimum(0.0), -0.0); - assert!((-0.0 as Float).minimum(0.0).is_sign_negative()); - assert_eq!((-0.0 as Float).minimum(-0.0), -0.0); - assert!((-0.0 as Float).minimum(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).minimum(9.0), 9.0); - assert_eq!((-9.0 as Float).minimum(0.0), -9.0); - assert_eq!((0.0 as Float).minimum(9.0), 0.0); - assert!((0.0 as Float).minimum(9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).minimum(9.0), -0.0); - assert!((-0.0 as Float).minimum(9.0).is_sign_negative()); - assert_eq!((-0.0 as Float).minimum(-9.0), -9.0); - assert_eq!(Float::INFINITY.minimum(9.0), 9.0); - assert_eq!((9.0 as Float).minimum(Float::INFINITY), 9.0); - assert_eq!(Float::INFINITY.minimum(-9.0), -9.0); - assert_eq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); - assert_eq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); - assert_eq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); - assert_eq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!((0.0 as Float).minimum(0.0), 0.0); + assert_biteq!((-0.0 as Float).minimum(0.0), -0.0); + assert_biteq!((-0.0 as Float).minimum(-0.0), -0.0); + assert_biteq!((9.0 as Float).minimum(9.0), 9.0); + assert_biteq!((-9.0 as Float).minimum(0.0), -9.0); + assert_biteq!((0.0 as Float).minimum(9.0), 0.0); + assert_biteq!((-0.0 as Float).minimum(9.0), -0.0); + assert_biteq!((-0.0 as Float).minimum(-9.0), -9.0); + assert_biteq!(Float::INFINITY.minimum(9.0), 9.0); + assert_biteq!((9.0 as Float).minimum(Float::INFINITY), 9.0); + assert_biteq!(Float::INFINITY.minimum(-9.0), -9.0); + assert_biteq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); + assert_biteq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); + assert_biteq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); + assert_biteq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); assert!(Float::NAN.minimum(9.0).is_nan()); assert!(Float::NAN.minimum(-9.0).is_nan()); assert!((9.0 as Float).minimum(Float::NAN).is_nan()); @@ -303,30 +329,23 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).maximum(0.0), 0.0); - assert!((0.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(0.0), 0.0); - assert!((-0.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(-0.0), -0.0); - assert!((-0.0 as Float).maximum(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).maximum(9.0), 9.0); - assert_eq!((-9.0 as Float).maximum(0.0), 0.0); - assert!((-9.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-9.0 as Float).maximum(-0.0), -0.0); - assert!((-9.0 as Float).maximum(-0.0).is_sign_negative()); - assert_eq!((0.0 as Float).maximum(9.0), 9.0); - assert_eq!((0.0 as Float).maximum(-9.0), 0.0); - assert!((0.0 as Float).maximum(-9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(-9.0), -0.0); - assert!((-0.0 as Float).maximum(-9.0).is_sign_negative()); - assert_eq!(Float::INFINITY.maximum(9.0), Float::INFINITY); - assert_eq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); - assert_eq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.maximum(9.0), 9.0); - assert_eq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); - assert_eq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); - assert_eq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); + assert_biteq!((0.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(-0.0), -0.0); + assert_biteq!((9.0 as Float).maximum(9.0), 9.0); + assert_biteq!((-9.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-9.0 as Float).maximum(-0.0), -0.0); + assert_biteq!((0.0 as Float).maximum(9.0), 9.0); + assert_biteq!((0.0 as Float).maximum(-9.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(-9.0), -0.0); + assert_biteq!(Float::INFINITY.maximum(9.0), Float::INFINITY); + assert_biteq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); + assert_biteq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.maximum(9.0), 9.0); + assert_biteq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); + assert_biteq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); + assert_biteq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); assert!(Float::NAN.maximum(9.0).is_nan()); assert!(Float::NAN.maximum(-9.0).is_nan()); assert!((9.0 as Float).maximum(Float::NAN).is_nan()); @@ -342,38 +361,38 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.5 as Float).midpoint(0.5), 0.5); - assert_eq!((0.5 as Float).midpoint(2.5), 1.5); - assert_eq!((3.0 as Float).midpoint(4.0), 3.5); - assert_eq!((-3.0 as Float).midpoint(4.0), 0.5); - assert_eq!((3.0 as Float).midpoint(-4.0), -0.5); - assert_eq!((-3.0 as Float).midpoint(-4.0), -3.5); - assert_eq!((0.0 as Float).midpoint(0.0), 0.0); - assert_eq!((-0.0 as Float).midpoint(-0.0), -0.0); - assert_eq!((-5.0 as Float).midpoint(5.0), 0.0); - assert_eq!(Float::MAX.midpoint(Float::MIN), 0.0); - assert_eq!(Float::MIN.midpoint(Float::MAX), -0.0); - assert_eq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); - assert_eq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); - assert_eq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); - assert_eq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); - assert_eq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); - assert_eq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); - assert_eq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); - assert_eq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); - assert_eq!(Float::MAX.midpoint(Float::MAX), Float::MAX); - assert_eq!( + assert_biteq!((0.5 as Float).midpoint(0.5), 0.5); + assert_biteq!((0.5 as Float).midpoint(2.5), 1.5); + assert_biteq!((3.0 as Float).midpoint(4.0), 3.5); + assert_biteq!((-3.0 as Float).midpoint(4.0), 0.5); + assert_biteq!((3.0 as Float).midpoint(-4.0), -0.5); + assert_biteq!((-3.0 as Float).midpoint(-4.0), -3.5); + assert_biteq!((0.0 as Float).midpoint(0.0), 0.0); + assert_biteq!((-0.0 as Float).midpoint(-0.0), -0.0); + assert_biteq!((-5.0 as Float).midpoint(5.0), 0.0); + assert_biteq!(Float::MAX.midpoint(Float::MIN), 0.0); + assert_biteq!(Float::MIN.midpoint(Float::MAX), 0.0); + assert_biteq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); + assert_biteq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_biteq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); + assert_biteq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_biteq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_biteq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_biteq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_biteq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_biteq!(Float::MAX.midpoint(Float::MAX), Float::MAX); + assert_biteq!( (Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE), Float::MIN_POSITIVE ); - assert_eq!( + assert_biteq!( (-Float::MIN_POSITIVE).midpoint(-Float::MIN_POSITIVE), -Float::MIN_POSITIVE ); - assert_eq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); - assert_eq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); - assert_eq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); - assert_eq!( + assert_biteq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); + assert_biteq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); + assert_biteq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); + assert_biteq!( Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), Float::NEG_INFINITY ); @@ -410,7 +429,7 @@ float_test! { let naive = (large + small) / 2.0; let midpoint = large.midpoint(small); - assert_eq!(naive, midpoint); + assert_biteq!(naive, midpoint); } } } @@ -423,10 +442,10 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((-1.0 as Float).abs(), 1.0); - assert_eq!((1.0 as Float).abs(), 1.0); - assert_eq!(Float::NEG_INFINITY.abs(), Float::INFINITY); - assert_eq!(Float::INFINITY.abs(), Float::INFINITY); + assert_biteq!((-1.0 as Float).abs(), 1.0); + assert_biteq!((1.0 as Float).abs(), 1.0); + assert_biteq!(Float::NEG_INFINITY.abs(), Float::INFINITY); + assert_biteq!(Float::INFINITY.abs(), Float::INFINITY); } } @@ -437,10 +456,10 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((1.0 as Float).copysign(-2.0), -1.0); - assert_eq!((-1.0 as Float).copysign(2.0), 1.0); - assert_eq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); + assert_biteq!((1.0 as Float).copysign(-2.0), -1.0); + assert_biteq!((-1.0 as Float).copysign(2.0), 1.0); + assert_biteq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); } } @@ -453,7 +472,7 @@ float_test! { }, test<Float> { assert!(Float::INFINITY.rem_euclid(42.0 as Float).is_nan()); - assert_eq!((42.0 as Float).rem_euclid(Float::INFINITY), (42.0 as Float)); + assert_biteq!((42.0 as Float).rem_euclid(Float::INFINITY), 42.0 as Float); assert!((42.0 as Float).rem_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.rem_euclid(Float::INFINITY).is_nan()); assert!(Float::INFINITY.rem_euclid(Float::NAN).is_nan()); @@ -469,7 +488,7 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); + assert_biteq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); assert!((42.0 as Float).div_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); assert!(Float::INFINITY.div_euclid(Float::NAN).is_nan()); @@ -484,20 +503,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).floor(), 0.0); - assert!((0.0 as Float).floor().is_sign_positive()); - assert_eq!((-0.0 as Float).floor(), -0.0); - assert!((-0.0 as Float).floor().is_sign_negative()); - assert_eq!((0.5 as Float).floor(), 0.0); - assert_eq!((-0.5 as Float).floor(), -1.0); - assert_eq!((1.5 as Float).floor(), 1.0); - assert_eq!(Float::MAX.floor(), Float::MAX); - assert_eq!(Float::MIN.floor(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.floor(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).floor(), -1.0); + assert_biteq!((0.0 as Float).floor(), 0.0); + assert_biteq!((-0.0 as Float).floor(), -0.0); + assert_biteq!((0.5 as Float).floor(), 0.0); + assert_biteq!((-0.5 as Float).floor(), -1.0); + assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!(Float::MAX.floor(), Float::MAX); + assert_biteq!(Float::MIN.floor(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.floor(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).floor(), -1.0); assert!(Float::NAN.floor().is_nan()); - assert_eq!(Float::INFINITY.floor(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.floor(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); } } @@ -508,19 +525,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).ceil(), 0.0); - assert!((0.0 as Float).ceil().is_sign_positive()); - assert_eq!((-0.0 as Float).ceil(), 0.0); - assert!((-0.0 as Float).ceil().is_sign_negative()); - assert_eq!((0.5 as Float).ceil(), 1.0); - assert_eq!((-0.5 as Float).ceil(), 0.0); - assert_eq!(Float::MAX.ceil(), Float::MAX); - assert_eq!(Float::MIN.ceil(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.ceil(), 1.0); - assert_eq!((-Float::MIN_POSITIVE).ceil(), 0.0); + assert_biteq!((0.0 as Float).ceil(), 0.0); + assert_biteq!((-0.0 as Float).ceil(), -0.0); + assert_biteq!((0.5 as Float).ceil(), 1.0); + assert_biteq!((-0.5 as Float).ceil(), -0.0); + assert_biteq!(Float::MAX.ceil(), Float::MAX); + assert_biteq!(Float::MIN.ceil(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.ceil(), 1.0); + assert_biteq!((-Float::MIN_POSITIVE).ceil(), -0.0); assert!(Float::NAN.ceil().is_nan()); - assert_eq!(Float::INFINITY.ceil(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.ceil(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); } } @@ -531,19 +546,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).round(), 0.0); - assert!((0.0 as Float).round().is_sign_positive()); - assert_eq!((-0.0 as Float).round(), -0.0); - assert!((-0.0 as Float).round().is_sign_negative()); - assert_eq!((0.5 as Float).round(), 1.0); - assert_eq!((-0.5 as Float).round(), -1.0); - assert_eq!(Float::MAX.round(), Float::MAX); - assert_eq!(Float::MIN.round(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.round(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).round(), 0.0); + assert_biteq!((0.0 as Float).round(), 0.0); + assert_biteq!((-0.0 as Float).round(), -0.0); + assert_biteq!((0.5 as Float).round(), 1.0); + assert_biteq!((-0.5 as Float).round(), -1.0); + assert_biteq!(Float::MAX.round(), Float::MAX); + assert_biteq!(Float::MIN.round(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.round(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).round(), -0.0); assert!(Float::NAN.round().is_nan()); - assert_eq!(Float::INFINITY.round(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.round(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); } } @@ -554,21 +567,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).round_ties_even(), 0.0); - assert!((0.0 as Float).round_ties_even().is_sign_positive()); - assert_eq!((-0.0 as Float).round_ties_even(), -0.0); - assert!((-0.0 as Float).round_ties_even().is_sign_negative()); - assert_eq!((0.5 as Float).round_ties_even(), 0.0); - assert!((0.5 as Float).round_ties_even().is_sign_positive()); - assert_eq!((-0.5 as Float).round_ties_even(), -0.0); - assert!((-0.5 as Float).round_ties_even().is_sign_negative()); - assert_eq!(Float::MAX.round_ties_even(), Float::MAX); - assert_eq!(Float::MIN.round_ties_even(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).round_ties_even(), 0.0); + assert_biteq!((0.0 as Float).round_ties_even(), 0.0); + assert_biteq!((-0.0 as Float).round_ties_even(), -0.0); + assert_biteq!((0.5 as Float).round_ties_even(), 0.0); + assert_biteq!((-0.5 as Float).round_ties_even(), -0.0); + assert_biteq!(Float::MAX.round_ties_even(), Float::MAX); + assert_biteq!(Float::MIN.round_ties_even(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).round_ties_even(), -0.0); assert!(Float::NAN.round_ties_even().is_nan()); - assert_eq!(Float::INFINITY.round_ties_even(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.round_ties_even(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); } } @@ -579,21 +588,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).trunc(), 0.0); - assert!((0.0 as Float).trunc().is_sign_positive()); - assert_eq!((-0.0 as Float).trunc(), -0.0); - assert!((-0.0 as Float).trunc().is_sign_negative()); - assert_eq!((0.5 as Float).trunc(), 0.0); - assert!((0.5 as Float).trunc().is_sign_positive()); - assert_eq!((-0.5 as Float).trunc(), -0.0); - assert!((-0.5 as Float).trunc().is_sign_negative()); - assert_eq!(Float::MAX.trunc(), Float::MAX); - assert_eq!(Float::MIN.trunc(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.trunc(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).trunc(), 0.0); + assert_biteq!((0.0 as Float).trunc(), 0.0); + assert_biteq!((-0.0 as Float).trunc(), -0.0); + assert_biteq!((0.5 as Float).trunc(), 0.0); + assert_biteq!((-0.5 as Float).trunc(), -0.0); + assert_biteq!(Float::MAX.trunc(), Float::MAX); + assert_biteq!(Float::MIN.trunc(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.trunc(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).trunc(), -0.0); assert!(Float::NAN.trunc().is_nan()); - assert_eq!(Float::INFINITY.trunc(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.trunc(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); } } @@ -604,19 +609,15 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { - assert_eq!((0.0 as Float).fract(), 0.0); - assert!((0.0 as Float).fract().is_sign_positive()); - assert_eq!((-0.0 as Float).fract(), 0.0); - assert!((-0.0 as Float).fract().is_sign_positive()); - assert_eq!((0.5 as Float).fract(), 0.5); - assert!((0.5 as Float).fract().is_sign_positive()); - assert_eq!((-0.5 as Float).fract(), -0.5); - assert!((-0.5 as Float).fract().is_sign_negative()); - assert_eq!(Float::MAX.fract(), 0.0); - assert_eq!(Float::MIN.fract(), 0.0); - assert_eq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); + assert_biteq!((0.0 as Float).fract(), 0.0); + assert_biteq!((-0.0 as Float).fract(), 0.0); + assert_biteq!((0.5 as Float).fract(), 0.5); + assert_biteq!((-0.5 as Float).fract(), -0.5); + assert_biteq!(Float::MAX.fract(), 0.0); + assert_biteq!(Float::MIN.fract(), 0.0); + assert_biteq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); assert!(Float::MIN_POSITIVE.fract().is_sign_positive()); - assert_eq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); + assert_biteq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); assert!((-Float::MIN_POSITIVE).fract().is_sign_negative()); assert!(Float::NAN.fract().is_nan()); assert!(Float::INFINITY.fract().is_nan()); From 42d52142abe913d7787b3e38e467029f1aca8dbd Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Mon, 9 Jun 2025 14:17:50 +0200 Subject: [PATCH 07/42] float tests: deduplicate min, max, and rounding tests --- coretests/tests/floats/f128.rs | 120 --------------------------------- coretests/tests/floats/f16.rs | 120 --------------------------------- coretests/tests/floats/f32.rs | 110 ------------------------------ coretests/tests/floats/f64.rs | 98 --------------------------- coretests/tests/floats/mod.rs | 64 +++++++++++++++--- 5 files changed, 56 insertions(+), 456 deletions(-) diff --git a/coretests/tests/floats/f128.rs b/coretests/tests/floats/f128.rs index ffa05715b2d53..cf78e8796a030 100644 --- a/coretests/tests/floats/f128.rs +++ b/coretests/tests/floats/f128.rs @@ -55,34 +55,6 @@ fn test_num_f128() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_min_nan() { - assert_biteq!(f128::NAN.min(2.0), 2.0); - assert_biteq!(2.0f128.min(f128::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_max_nan() { - assert_biteq!(f128::NAN.max(2.0), 2.0); - assert_biteq!(2.0f128.max(f128::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_minimum() { - assert!(f128::NAN.minimum(2.0).is_nan()); - assert!(2.0f128.minimum(f128::NAN).is_nan()); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_maximum() { - assert!(f128::NAN.maximum(2.0).is_nan()); - assert!(2.0f128.maximum(f128::NAN).is_nan()); -} - #[test] fn test_nan() { let nan: f128 = f128::NAN; @@ -234,98 +206,6 @@ fn test_classify() { assert_eq!(1e-4932f128.classify(), Fp::Subnormal); } -#[test] -#[cfg(target_has_reliable_f128_math)] -fn test_floor() { - assert_biteq!(1.0f128.floor(), 1.0f128); - assert_biteq!(1.3f128.floor(), 1.0f128); - assert_biteq!(1.5f128.floor(), 1.0f128); - assert_biteq!(1.7f128.floor(), 1.0f128); - assert_biteq!(0.0f128.floor(), 0.0f128); - assert_biteq!((-0.0f128).floor(), -0.0f128); - assert_biteq!((-1.0f128).floor(), -1.0f128); - assert_biteq!((-1.3f128).floor(), -2.0f128); - assert_biteq!((-1.5f128).floor(), -2.0f128); - assert_biteq!((-1.7f128).floor(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_ceil() { - assert_biteq!(1.0f128.ceil(), 1.0f128); - assert_biteq!(1.3f128.ceil(), 2.0f128); - assert_biteq!(1.5f128.ceil(), 2.0f128); - assert_biteq!(1.7f128.ceil(), 2.0f128); - assert_biteq!(0.0f128.ceil(), 0.0f128); - assert_biteq!((-0.0f128).ceil(), -0.0f128); - assert_biteq!((-1.0f128).ceil(), -1.0f128); - assert_biteq!((-1.3f128).ceil(), -1.0f128); - assert_biteq!((-1.5f128).ceil(), -1.0f128); - assert_biteq!((-1.7f128).ceil(), -1.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_round() { - assert_biteq!(2.5f128.round(), 3.0f128); - assert_biteq!(1.0f128.round(), 1.0f128); - assert_biteq!(1.3f128.round(), 1.0f128); - assert_biteq!(1.5f128.round(), 2.0f128); - assert_biteq!(1.7f128.round(), 2.0f128); - assert_biteq!(0.0f128.round(), 0.0f128); - assert_biteq!((-0.0f128).round(), -0.0f128); - assert_biteq!((-1.0f128).round(), -1.0f128); - assert_biteq!((-1.3f128).round(), -1.0f128); - assert_biteq!((-1.5f128).round(), -2.0f128); - assert_biteq!((-1.7f128).round(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_round_ties_even() { - assert_biteq!(2.5f128.round_ties_even(), 2.0f128); - assert_biteq!(1.0f128.round_ties_even(), 1.0f128); - assert_biteq!(1.3f128.round_ties_even(), 1.0f128); - assert_biteq!(1.5f128.round_ties_even(), 2.0f128); - assert_biteq!(1.7f128.round_ties_even(), 2.0f128); - assert_biteq!(0.0f128.round_ties_even(), 0.0f128); - assert_biteq!((-0.0f128).round_ties_even(), -0.0f128); - assert_biteq!((-1.0f128).round_ties_even(), -1.0f128); - assert_biteq!((-1.3f128).round_ties_even(), -1.0f128); - assert_biteq!((-1.5f128).round_ties_even(), -2.0f128); - assert_biteq!((-1.7f128).round_ties_even(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_trunc() { - assert_biteq!(1.0f128.trunc(), 1.0f128); - assert_biteq!(1.3f128.trunc(), 1.0f128); - assert_biteq!(1.5f128.trunc(), 1.0f128); - assert_biteq!(1.7f128.trunc(), 1.0f128); - assert_biteq!(0.0f128.trunc(), 0.0f128); - assert_biteq!((-0.0f128).trunc(), -0.0f128); - assert_biteq!((-1.0f128).trunc(), -1.0f128); - assert_biteq!((-1.3f128).trunc(), -1.0f128); - assert_biteq!((-1.5f128).trunc(), -1.0f128); - assert_biteq!((-1.7f128).trunc(), -1.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_fract() { - assert_biteq!(1.0f128.fract(), 0.0f128); - assert_biteq!(1.3f128.fract(), 0.300000000000000000000000000000000039f128); - assert_biteq!(1.5f128.fract(), 0.5f128); - assert_biteq!(1.7f128.fract(), 0.7f128); - assert_biteq!(0.0f128.fract(), 0.0f128); - assert_biteq!((-0.0f128).fract(), 0.0f128); - assert_biteq!((-1.0f128).fract(), 0.0f128); - assert_biteq!((-1.3f128).fract(), -0.300000000000000000000000000000000039f128); - assert_biteq!((-1.5f128).fract(), -0.5f128); - assert_biteq!((-1.7f128).fract(), -0.699999999999999999999999999999999961f128); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/coretests/tests/floats/f16.rs b/coretests/tests/floats/f16.rs index 7e8ce99dbe081..9e91b654304b6 100644 --- a/coretests/tests/floats/f16.rs +++ b/coretests/tests/floats/f16.rs @@ -51,34 +51,6 @@ fn test_num_f16() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_min_nan() { - assert_biteq!(f16::NAN.min(2.0), 2.0); - assert_biteq!(2.0f16.min(f16::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_max_nan() { - assert_biteq!(f16::NAN.max(2.0), 2.0); - assert_biteq!(2.0f16.max(f16::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_minimum() { - assert!(f16::NAN.minimum(2.0).is_nan()); - assert!(2.0f16.minimum(f16::NAN).is_nan()); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_maximum() { - assert!(f16::NAN.maximum(2.0).is_nan()); - assert!(2.0f16.maximum(f16::NAN).is_nan()); -} - #[test] fn test_nan() { let nan: f16 = f16::NAN; @@ -230,98 +202,6 @@ fn test_classify() { assert_eq!(1e-5f16.classify(), Fp::Subnormal); } -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_floor() { - assert_biteq!(1.0f16.floor(), 1.0f16); - assert_biteq!(1.3f16.floor(), 1.0f16); - assert_biteq!(1.5f16.floor(), 1.0f16); - assert_biteq!(1.7f16.floor(), 1.0f16); - assert_biteq!(0.0f16.floor(), 0.0f16); - assert_biteq!((-0.0f16).floor(), -0.0f16); - assert_biteq!((-1.0f16).floor(), -1.0f16); - assert_biteq!((-1.3f16).floor(), -2.0f16); - assert_biteq!((-1.5f16).floor(), -2.0f16); - assert_biteq!((-1.7f16).floor(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_ceil() { - assert_biteq!(1.0f16.ceil(), 1.0f16); - assert_biteq!(1.3f16.ceil(), 2.0f16); - assert_biteq!(1.5f16.ceil(), 2.0f16); - assert_biteq!(1.7f16.ceil(), 2.0f16); - assert_biteq!(0.0f16.ceil(), 0.0f16); - assert_biteq!((-0.0f16).ceil(), -0.0f16); - assert_biteq!((-1.0f16).ceil(), -1.0f16); - assert_biteq!((-1.3f16).ceil(), -1.0f16); - assert_biteq!((-1.5f16).ceil(), -1.0f16); - assert_biteq!((-1.7f16).ceil(), -1.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_round() { - assert_biteq!(2.5f16.round(), 3.0f16); - assert_biteq!(1.0f16.round(), 1.0f16); - assert_biteq!(1.3f16.round(), 1.0f16); - assert_biteq!(1.5f16.round(), 2.0f16); - assert_biteq!(1.7f16.round(), 2.0f16); - assert_biteq!(0.0f16.round(), 0.0f16); - assert_biteq!((-0.0f16).round(), -0.0f16); - assert_biteq!((-1.0f16).round(), -1.0f16); - assert_biteq!((-1.3f16).round(), -1.0f16); - assert_biteq!((-1.5f16).round(), -2.0f16); - assert_biteq!((-1.7f16).round(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_round_ties_even() { - assert_biteq!(2.5f16.round_ties_even(), 2.0f16); - assert_biteq!(1.0f16.round_ties_even(), 1.0f16); - assert_biteq!(1.3f16.round_ties_even(), 1.0f16); - assert_biteq!(1.5f16.round_ties_even(), 2.0f16); - assert_biteq!(1.7f16.round_ties_even(), 2.0f16); - assert_biteq!(0.0f16.round_ties_even(), 0.0f16); - assert_biteq!((-0.0f16).round_ties_even(), -0.0f16); - assert_biteq!((-1.0f16).round_ties_even(), -1.0f16); - assert_biteq!((-1.3f16).round_ties_even(), -1.0f16); - assert_biteq!((-1.5f16).round_ties_even(), -2.0f16); - assert_biteq!((-1.7f16).round_ties_even(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_trunc() { - assert_biteq!(1.0f16.trunc(), 1.0f16); - assert_biteq!(1.3f16.trunc(), 1.0f16); - assert_biteq!(1.5f16.trunc(), 1.0f16); - assert_biteq!(1.7f16.trunc(), 1.0f16); - assert_biteq!(0.0f16.trunc(), 0.0f16); - assert_biteq!((-0.0f16).trunc(), -0.0f16); - assert_biteq!((-1.0f16).trunc(), -1.0f16); - assert_biteq!((-1.3f16).trunc(), -1.0f16); - assert_biteq!((-1.5f16).trunc(), -1.0f16); - assert_biteq!((-1.7f16).trunc(), -1.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_fract() { - assert_biteq!(1.0f16.fract(), 0.0f16); - assert_biteq!(1.3f16.fract(), 0.2998f16); - assert_biteq!(1.5f16.fract(), 0.5f16); - assert_biteq!(1.7f16.fract(), 0.7f16); - assert_biteq!(0.0f16.fract(), 0.0f16); - assert_biteq!((-0.0f16).fract(), 0.0f16); - assert_biteq!((-1.0f16).fract(), 0.0f16); - assert_biteq!((-1.3f16).fract(), -0.2998f16); - assert_biteq!((-1.5f16).fract(), -0.5f16); - assert_biteq!((-1.7f16).fract(), -0.7f16); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/coretests/tests/floats/f32.rs b/coretests/tests/floats/f32.rs index 460aecaac6470..08a16e7c440f2 100644 --- a/coretests/tests/floats/f32.rs +++ b/coretests/tests/floats/f32.rs @@ -30,30 +30,6 @@ fn test_num_f32() { super::test_num(10f32, 2f32); } -#[test] -fn test_min_nan() { - assert_biteq!(f32::NAN.min(2.0), 2.0); - assert_biteq!(2.0f32.min(f32::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_biteq!(f32::NAN.max(2.0), 2.0); - assert_biteq!(2.0f32.max(f32::NAN), 2.0); -} - -#[test] -fn test_minimum() { - assert!(f32::NAN.minimum(2.0).is_nan()); - assert!(2.0f32.minimum(f32::NAN).is_nan()); -} - -#[test] -fn test_maximum() { - assert!(f32::NAN.maximum(2.0).is_nan()); - assert!(2.0f32.maximum(f32::NAN).is_nan()); -} - #[test] fn test_nan() { let nan: f32 = f32::NAN; @@ -205,92 +181,6 @@ fn test_classify() { assert_eq!(1e-38f32.classify(), Fp::Subnormal); } -#[test] -fn test_floor() { - assert_biteq!(f32::math::floor(1.0f32), 1.0f32); - assert_biteq!(f32::math::floor(1.3f32), 1.0f32); - assert_biteq!(f32::math::floor(1.5f32), 1.0f32); - assert_biteq!(f32::math::floor(1.7f32), 1.0f32); - assert_biteq!(f32::math::floor(0.0f32), 0.0f32); - assert_biteq!(f32::math::floor(-0.0f32), -0.0f32); - assert_biteq!(f32::math::floor(-1.0f32), -1.0f32); - assert_biteq!(f32::math::floor(-1.3f32), -2.0f32); - assert_biteq!(f32::math::floor(-1.5f32), -2.0f32); - assert_biteq!(f32::math::floor(-1.7f32), -2.0f32); -} - -#[test] -fn test_ceil() { - assert_biteq!(f32::math::ceil(1.0f32), 1.0f32); - assert_biteq!(f32::math::ceil(1.3f32), 2.0f32); - assert_biteq!(f32::math::ceil(1.5f32), 2.0f32); - assert_biteq!(f32::math::ceil(1.7f32), 2.0f32); - assert_biteq!(f32::math::ceil(0.0f32), 0.0f32); - assert_biteq!(f32::math::ceil(-0.0f32), -0.0f32); - assert_biteq!(f32::math::ceil(-1.0f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.3f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.5f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.7f32), -1.0f32); -} - -#[test] -fn test_round() { - assert_biteq!(f32::math::round(2.5f32), 3.0f32); - assert_biteq!(f32::math::round(1.0f32), 1.0f32); - assert_biteq!(f32::math::round(1.3f32), 1.0f32); - assert_biteq!(f32::math::round(1.5f32), 2.0f32); - assert_biteq!(f32::math::round(1.7f32), 2.0f32); - assert_biteq!(f32::math::round(0.0f32), 0.0f32); - assert_biteq!(f32::math::round(-0.0f32), -0.0f32); - assert_biteq!(f32::math::round(-1.0f32), -1.0f32); - assert_biteq!(f32::math::round(-1.3f32), -1.0f32); - assert_biteq!(f32::math::round(-1.5f32), -2.0f32); - assert_biteq!(f32::math::round(-1.7f32), -2.0f32); -} - -#[test] -fn test_round_ties_even() { - assert_biteq!(f32::math::round_ties_even(2.5f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(1.0f32), 1.0f32); - assert_biteq!(f32::math::round_ties_even(1.3f32), 1.0f32); - assert_biteq!(f32::math::round_ties_even(1.5f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(1.7f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(0.0f32), 0.0f32); - assert_biteq!(f32::math::round_ties_even(-0.0f32), -0.0f32); - assert_biteq!(f32::math::round_ties_even(-1.0f32), -1.0f32); - assert_biteq!(f32::math::round_ties_even(-1.3f32), -1.0f32); - assert_biteq!(f32::math::round_ties_even(-1.5f32), -2.0f32); - assert_biteq!(f32::math::round_ties_even(-1.7f32), -2.0f32); -} - -#[test] -fn test_trunc() { - assert_biteq!(f32::math::trunc(1.0f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.3f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.5f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.7f32), 1.0f32); - assert_biteq!(f32::math::trunc(0.0f32), 0.0f32); - assert_biteq!(f32::math::trunc(-0.0f32), -0.0f32); - assert_biteq!(f32::math::trunc(-1.0f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.3f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.5f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.7f32), -1.0f32); -} - -#[test] -fn test_fract() { - assert_biteq!(f32::math::fract(1.0f32), 0.0f32); - assert_biteq!(f32::math::fract(1.3f32), 0.29999995f32); - assert_biteq!(f32::math::fract(1.5f32), 0.5f32); - assert_biteq!(f32::math::fract(1.7f32), 0.70000005f32); - assert_biteq!(f32::math::fract(0.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-0.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-1.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-1.3f32), -0.29999995f32); - assert_biteq!(f32::math::fract(-1.5f32), -0.5f32); - assert_biteq!(f32::math::fract(-1.7f32), -0.70000005f32); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/coretests/tests/floats/f64.rs b/coretests/tests/floats/f64.rs index 1dfce22c14afe..97abb01bfab72 100644 --- a/coretests/tests/floats/f64.rs +++ b/coretests/tests/floats/f64.rs @@ -30,18 +30,6 @@ fn test_num_f64() { super::test_num(10f64, 2f64); } -#[test] -fn test_min_nan() { - assert_biteq!(f64::NAN.min(2.0), 2.0); - assert_biteq!(2.0f64.min(f64::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_biteq!(f64::NAN.max(2.0), 2.0); - assert_biteq!(2.0f64.max(f64::NAN), 2.0); -} - #[test] fn test_nan() { let nan: f64 = f64::NAN; @@ -192,92 +180,6 @@ fn test_classify() { assert_eq!(1e-308f64.classify(), Fp::Subnormal); } -#[test] -fn test_floor() { - assert_biteq!(f64::math::floor(1.0f64), 1.0f64); - assert_biteq!(f64::math::floor(1.3f64), 1.0f64); - assert_biteq!(f64::math::floor(1.5f64), 1.0f64); - assert_biteq!(f64::math::floor(1.7f64), 1.0f64); - assert_biteq!(f64::math::floor(0.0f64), 0.0f64); - assert_biteq!(f64::math::floor(-0.0f64), -0.0f64); - assert_biteq!(f64::math::floor(-1.0f64), -1.0f64); - assert_biteq!(f64::math::floor(-1.3f64), -2.0f64); - assert_biteq!(f64::math::floor(-1.5f64), -2.0f64); - assert_biteq!(f64::math::floor(-1.7f64), -2.0f64); -} - -#[test] -fn test_ceil() { - assert_biteq!(f64::math::ceil(1.0f64), 1.0f64); - assert_biteq!(f64::math::ceil(1.3f64), 2.0f64); - assert_biteq!(f64::math::ceil(1.5f64), 2.0f64); - assert_biteq!(f64::math::ceil(1.7f64), 2.0f64); - assert_biteq!(f64::math::ceil(0.0f64), 0.0f64); - assert_biteq!(f64::math::ceil(-0.0f64), -0.0f64); - assert_biteq!(f64::math::ceil(-1.0f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.3f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.5f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.7f64), -1.0f64); -} - -#[test] -fn test_round() { - assert_biteq!(f64::math::round(2.5f64), 3.0f64); - assert_biteq!(f64::math::round(1.0f64), 1.0f64); - assert_biteq!(f64::math::round(1.3f64), 1.0f64); - assert_biteq!(f64::math::round(1.5f64), 2.0f64); - assert_biteq!(f64::math::round(1.7f64), 2.0f64); - assert_biteq!(f64::math::round(0.0f64), 0.0f64); - assert_biteq!(f64::math::round(-0.0f64), -0.0f64); - assert_biteq!(f64::math::round(-1.0f64), -1.0f64); - assert_biteq!(f64::math::round(-1.3f64), -1.0f64); - assert_biteq!(f64::math::round(-1.5f64), -2.0f64); - assert_biteq!(f64::math::round(-1.7f64), -2.0f64); -} - -#[test] -fn test_round_ties_even() { - assert_biteq!(f64::math::round_ties_even(2.5f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(1.0f64), 1.0f64); - assert_biteq!(f64::math::round_ties_even(1.3f64), 1.0f64); - assert_biteq!(f64::math::round_ties_even(1.5f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(1.7f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(0.0f64), 0.0f64); - assert_biteq!(f64::math::round_ties_even(-0.0f64), -0.0f64); - assert_biteq!(f64::math::round_ties_even(-1.0f64), -1.0f64); - assert_biteq!(f64::math::round_ties_even(-1.3f64), -1.0f64); - assert_biteq!(f64::math::round_ties_even(-1.5f64), -2.0f64); - assert_biteq!(f64::math::round_ties_even(-1.7f64), -2.0f64); -} - -#[test] -fn test_trunc() { - assert_biteq!(f64::math::trunc(1.0f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.3f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.5f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.7f64), 1.0f64); - assert_biteq!(f64::math::trunc(0.0f64), 0.0f64); - assert_biteq!(f64::math::trunc(-0.0f64), -0.0f64); - assert_biteq!(f64::math::trunc(-1.0f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.3f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.5f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.7f64), -1.0f64); -} - -#[test] -fn test_fract() { - assert_biteq!(f64::math::fract(1.0f64), 0.0f64); - assert_biteq!(f64::math::fract(1.3f64), 0.30000000000000004f64); - assert_biteq!(f64::math::fract(1.5f64), 0.5f64); - assert_biteq!(f64::math::fract(1.7f64), 0.7f64); - assert_biteq!(f64::math::fract(0.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-0.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-1.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-1.3f64), -0.30000000000000004f64); - assert_biteq!(f64::math::fract(-1.5f64), -0.5f64); - assert_biteq!(f64::math::fract(-1.7f64), -0.69999999999999996f64); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index a2b0d6caf13e9..c76736803a1ec 100644 --- a/coretests/tests/floats/mod.rs +++ b/coretests/tests/floats/mod.rs @@ -54,7 +54,6 @@ macro_rules! assert_biteq_ { } pub(crate) use assert_biteq_ as assert_biteq; -#[allow(unused)] mod const_asserts { // Shadow some assert implementations that would otherwise not compile in a const-context. // Every macro added here also needs to be added in the `float_test!` macro below. @@ -503,11 +502,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { + assert_biteq!((1.0 as Float).floor(), 1.0); + assert_biteq!((1.3 as Float).floor(), 1.0); + assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!((1.7 as Float).floor(), 1.0); + assert_biteq!((0.5 as Float).floor(), 0.0); assert_biteq!((0.0 as Float).floor(), 0.0); assert_biteq!((-0.0 as Float).floor(), -0.0); - assert_biteq!((0.5 as Float).floor(), 0.0); assert_biteq!((-0.5 as Float).floor(), -1.0); - assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!((-1.0 as Float).floor(), -1.0); + assert_biteq!((-1.3 as Float).floor(), -2.0); + assert_biteq!((-1.5 as Float).floor(), -2.0); + assert_biteq!((-1.7 as Float).floor(), -2.0); assert_biteq!(Float::MAX.floor(), Float::MAX); assert_biteq!(Float::MIN.floor(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.floor(), 0.0); @@ -525,10 +531,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { + assert_biteq!((1.0 as Float).ceil(), 1.0); + assert_biteq!((1.3 as Float).ceil(), 2.0); + assert_biteq!((1.5 as Float).ceil(), 2.0); + assert_biteq!((1.7 as Float).ceil(), 2.0); + assert_biteq!((0.5 as Float).ceil(), 1.0); assert_biteq!((0.0 as Float).ceil(), 0.0); assert_biteq!((-0.0 as Float).ceil(), -0.0); - assert_biteq!((0.5 as Float).ceil(), 1.0); assert_biteq!((-0.5 as Float).ceil(), -0.0); + assert_biteq!((-1.0 as Float).ceil(), -1.0); + assert_biteq!((-1.3 as Float).ceil(), -1.0); + assert_biteq!((-1.5 as Float).ceil(), -1.0); + assert_biteq!((-1.7 as Float).ceil(), -1.0); assert_biteq!(Float::MAX.ceil(), Float::MAX); assert_biteq!(Float::MIN.ceil(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.ceil(), 1.0); @@ -546,10 +560,19 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { + assert_biteq!((2.5 as Float).round(), 3.0); + assert_biteq!((1.0 as Float).round(), 1.0); + assert_biteq!((1.3 as Float).round(), 1.0); + assert_biteq!((1.5 as Float).round(), 2.0); + assert_biteq!((1.7 as Float).round(), 2.0); + assert_biteq!((0.5 as Float).round(), 1.0); assert_biteq!((0.0 as Float).round(), 0.0); assert_biteq!((-0.0 as Float).round(), -0.0); - assert_biteq!((0.5 as Float).round(), 1.0); assert_biteq!((-0.5 as Float).round(), -1.0); + assert_biteq!((-1.0 as Float).round(), -1.0); + assert_biteq!((-1.3 as Float).round(), -1.0); + assert_biteq!((-1.5 as Float).round(), -2.0); + assert_biteq!((-1.7 as Float).round(), -2.0); assert_biteq!(Float::MAX.round(), Float::MAX); assert_biteq!(Float::MIN.round(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.round(), 0.0); @@ -567,10 +590,19 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { + assert_biteq!((2.5 as Float).round_ties_even(), 2.0); + assert_biteq!((1.0 as Float).round_ties_even(), 1.0); + assert_biteq!((1.3 as Float).round_ties_even(), 1.0); + assert_biteq!((1.5 as Float).round_ties_even(), 2.0); + assert_biteq!((1.7 as Float).round_ties_even(), 2.0); + assert_biteq!((0.5 as Float).round_ties_even(), 0.0); assert_biteq!((0.0 as Float).round_ties_even(), 0.0); assert_biteq!((-0.0 as Float).round_ties_even(), -0.0); - assert_biteq!((0.5 as Float).round_ties_even(), 0.0); assert_biteq!((-0.5 as Float).round_ties_even(), -0.0); + assert_biteq!((-1.0 as Float).round_ties_even(), -1.0); + assert_biteq!((-1.3 as Float).round_ties_even(), -1.0); + assert_biteq!((-1.5 as Float).round_ties_even(), -2.0); + assert_biteq!((-1.7 as Float).round_ties_even(), -2.0); assert_biteq!(Float::MAX.round_ties_even(), Float::MAX); assert_biteq!(Float::MIN.round_ties_even(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); @@ -588,10 +620,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { + assert_biteq!((1.0 as Float).trunc(), 1.0); + assert_biteq!((1.3 as Float).trunc(), 1.0); + assert_biteq!((1.5 as Float).trunc(), 1.0); + assert_biteq!((1.7 as Float).trunc(), 1.0); + assert_biteq!((0.5 as Float).trunc(), 0.0); assert_biteq!((0.0 as Float).trunc(), 0.0); assert_biteq!((-0.0 as Float).trunc(), -0.0); - assert_biteq!((0.5 as Float).trunc(), 0.0); assert_biteq!((-0.5 as Float).trunc(), -0.0); + assert_biteq!((-1.0 as Float).trunc(), -1.0); + assert_biteq!((-1.3 as Float).trunc(), -1.0); + assert_biteq!((-1.5 as Float).trunc(), -1.0); + assert_biteq!((-1.7 as Float).trunc(), -1.0); assert_biteq!(Float::MAX.trunc(), Float::MAX); assert_biteq!(Float::MIN.trunc(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.trunc(), 0.0); @@ -609,10 +649,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test<Float> { + assert_biteq!((1.0 as Float).fract(), 0.0); + assert_approx_eq!((1.3 as Float).fract(), 0.3, 1e-3); // rounding differs between float types + assert_biteq!((1.5 as Float).fract(), 0.5); + assert_approx_eq!((1.7 as Float).fract(), 0.7); + assert_biteq!((0.5 as Float).fract(), 0.5); assert_biteq!((0.0 as Float).fract(), 0.0); assert_biteq!((-0.0 as Float).fract(), 0.0); - assert_biteq!((0.5 as Float).fract(), 0.5); assert_biteq!((-0.5 as Float).fract(), -0.5); + assert_biteq!((-1.0 as Float).fract(), 0.0); + assert_approx_eq!((-1.3 as Float).fract(), -0.3, 1e-3); // rounding differs between float types + assert_biteq!((-1.5 as Float).fract(), -0.5); + assert_approx_eq!((-1.7 as Float).fract(), -0.7); assert_biteq!(Float::MAX.fract(), 0.0); assert_biteq!(Float::MIN.fract(), 0.0); assert_biteq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); From 47943327010731f8ea5a45d6056721b5501f7fd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Mon, 9 Jun 2025 13:51:09 +0200 Subject: [PATCH 08/42] make the default float comparison tolerance type-dependent --- coretests/tests/floats/mod.rs | 46 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index c76736803a1ec..6288ff23afeac 100644 --- a/coretests/tests/floats/mod.rs +++ b/coretests/tests/floats/mod.rs @@ -1,9 +1,32 @@ use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. +/// Set the default tolerance for float comparison based on the type. +trait Approx { + const LIM: Self; +} + +impl Approx for f16 { + const LIM: Self = 1e-3; +} +impl Approx for f32 { + const LIM: Self = 1e-6; +} +impl Approx for f64 { + const LIM: Self = 1e-6; +} +impl Approx for f128 { + const LIM: Self = 1e-9; +} + +/// Determine the tolerance for values of the argument type. +const fn lim_for_ty<T: Approx + Copy>(_x: T) -> T { + T::LIM +} + +/// Verify that floats are within a tolerance of each other. macro_rules! assert_approx_eq_ { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -57,15 +80,6 @@ pub(crate) use assert_biteq_ as assert_biteq; mod const_asserts { // Shadow some assert implementations that would otherwise not compile in a const-context. // Every macro added here also needs to be added in the `float_test!` macro below. - macro_rules! assert_eq { - ($left:expr, $right:expr $(,)?) => { - std::assert!($left == $right) - }; - ($left:expr, $right:expr, $($arg:tt)+) => { - std::assert!($left == $right, $($arg)+) - }; - } - pub(crate) use assert_eq; macro_rules! assert_biteq { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ @@ -94,7 +108,7 @@ mod const_asserts { pub(crate) use assert_biteq; macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -171,7 +185,9 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use $crate::floats::const_asserts::{assert_eq, assert_biteq, assert_approx_eq}; + use super::Approx; + #[allow(unused)] + use $crate::floats::const_asserts::{assert_biteq, assert_approx_eq}; #[test] $( $( #[$f16_const_meta] )+ )? @@ -650,7 +666,7 @@ float_test! { }, test<Float> { assert_biteq!((1.0 as Float).fract(), 0.0); - assert_approx_eq!((1.3 as Float).fract(), 0.3, 1e-3); // rounding differs between float types + assert_approx_eq!((1.3 as Float).fract(), 0.3); // rounding differs between float types assert_biteq!((1.5 as Float).fract(), 0.5); assert_approx_eq!((1.7 as Float).fract(), 0.7); assert_biteq!((0.5 as Float).fract(), 0.5); @@ -658,7 +674,7 @@ float_test! { assert_biteq!((-0.0 as Float).fract(), 0.0); assert_biteq!((-0.5 as Float).fract(), -0.5); assert_biteq!((-1.0 as Float).fract(), 0.0); - assert_approx_eq!((-1.3 as Float).fract(), -0.3, 1e-3); // rounding differs between float types + assert_approx_eq!((-1.3 as Float).fract(), -0.3); // rounding differs between float types assert_biteq!((-1.5 as Float).fract(), -0.5); assert_approx_eq!((-1.7 as Float).fract(), -0.7); assert_biteq!(Float::MAX.fract(), 0.0); From b734b89a02fd307b9afcc762737b50e525f1e498 Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Mon, 9 Jun 2025 14:05:24 +0200 Subject: [PATCH 09/42] float midpoint tests: add missing NAN cases --- coretests/tests/floats/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index 6288ff23afeac..8f15a2625af07 100644 --- a/coretests/tests/floats/mod.rs +++ b/coretests/tests/floats/mod.rs @@ -411,6 +411,8 @@ float_test! { Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), Float::NEG_INFINITY ); + assert!(Float::NEG_INFINITY.midpoint(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.midpoint(Float::NEG_INFINITY).is_nan()); assert!(Float::NAN.midpoint(1.0).is_nan()); assert!((1.0 as Float).midpoint(Float::NAN).is_nan()); assert!(Float::NAN.midpoint(Float::NAN).is_nan()); From d232aa28420bbf32c9b87004c87e8bcf15f8308a Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Tue, 10 Jun 2025 06:49:28 +0000 Subject: [PATCH 10/42] compiler-builtins: Remove unused `lints.rust` table The unexpected configs are now unused or known to `rustc` in our CI. --- compiler-builtins/compiler-builtins/Cargo.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler-builtins/compiler-builtins/Cargo.toml b/compiler-builtins/compiler-builtins/Cargo.toml index 11ee919543841..eabb3d6259943 100644 --- a/compiler-builtins/compiler-builtins/Cargo.toml +++ b/compiler-builtins/compiler-builtins/Cargo.toml @@ -55,7 +55,3 @@ rustc-dep-of-std = ["compiler-builtins", "dep:core"] # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] - -[lints.rust] -# The cygwin config can be dropped after our benchmark toolchain is bumped -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)', 'cfg(target_os, values("cygwin"))'] } From 3e892fc4ef8960c4ce6b70552fb5cc5ce5d31de8 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Tue, 10 Jun 2025 07:02:57 +0000 Subject: [PATCH 11/42] ci: Fix a typo that was causing a command failure --- compiler-builtins/ci/bench-icount.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-builtins/ci/bench-icount.sh b/compiler-builtins/ci/bench-icount.sh index 5724955fe3672..d2baebb52d8fd 100755 --- a/compiler-builtins/ci/bench-icount.sh +++ b/compiler-builtins/ci/bench-icount.sh @@ -57,7 +57,7 @@ function run_icount_benchmarks() { # Disregard regressions after merge echo "Benchmarks completed with regressions; ignoring (not in a PR)" else - ./ci/ci-util.py handle-banch-regressions "$PR_NUMBER" + ./ci/ci-util.py handle-bench-regressions "$PR_NUMBER" fi } From cdfe5084457789fb6b0a40fc92ffe6edea1f5969 Mon Sep 17 00:00:00 2001 From: Gray Olson <gray@grayolson.com> Date: Tue, 10 Jun 2025 16:59:21 +0200 Subject: [PATCH 12/42] core docs: improve clarity of considerations about atomic CAS operations - Rewords existing Considerations section on `fetch_update` and friends to make clear that the limitations are inherent to an implementation based on any CAS operation, rather than the weak version of `compare_exchange` in particular - Add Considerations to `compare_exchange` and `compare_exchange_weak` which details similar considerations and when they may be relevant. --- core/src/sync/atomic.rs | 179 ++++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 33 deletions(-) diff --git a/core/src/sync/atomic.rs b/core/src/sync/atomic.rs index 4f9f2936564ff..04c8d1473b048 100644 --- a/core/src/sync/atomic.rs +++ b/core/src/sync/atomic.rs @@ -891,6 +891,19 @@ impl AtomicBool { /// Err(false)); /// assert_eq!(some_bool.load(Ordering::Relaxed), false); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the + /// [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] @@ -973,6 +986,19 @@ impl AtomicBool { /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the + /// [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] @@ -1271,11 +1297,14 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1338,11 +1367,14 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1393,11 +1425,14 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> { /// let value = some_ptr.compare_exchange(ptr, other_ptr, /// Ordering::SeqCst, Ordering::Relaxed); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] @@ -1874,6 +1923,20 @@ impl<T> AtomicPtr<T> { /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] @@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -2967,6 +3042,20 @@ macro_rules! atomic_int { /// Err(10)); /// assert_eq!(some_var.load(Ordering::Relaxed), 10); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim! This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[$stable_cxchg] #[$cfg_cas] @@ -3016,6 +3105,20 @@ macro_rules! atomic_int { /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[$stable_cxchg] #[$cfg_cas] @@ -3246,13 +3349,16 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -3309,13 +3415,16 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -3367,13 +3476,17 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// From 2b61cdc74f21b4fb1e2e81ecfd1a08dcfb977381 Mon Sep 17 00:00:00 2001 From: Mara Bos <m-ou.se@m-ou.se> Date: Wed, 11 Jun 2025 18:28:05 +0200 Subject: [PATCH 13/42] Fix Debug for Location. --- core/src/panic/location.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/src/panic/location.rs b/core/src/panic/location.rs index 94cfd667ffae0..f1eedede8aab9 100644 --- a/core/src/panic/location.rs +++ b/core/src/panic/location.rs @@ -30,7 +30,7 @@ use crate::fmt; /// Files are compared as strings, not `Path`, which could be unexpected. /// See [`Location::file`]'s documentation for more discussion. #[lang = "panic_location"] -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "panic_hooks", since = "1.10.0")] pub struct Location<'a> { // Note: this filename will have exactly one nul byte at its end, but otherwise @@ -43,6 +43,17 @@ pub struct Location<'a> { col: u32, } +#[stable(feature = "panic_hooks", since = "1.10.0")] +impl fmt::Debug for Location<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Location") + .field("file", &self.file()) + .field("line", &self.line) + .field("column", &self.col) + .finish() + } +} + impl<'a> Location<'a> { /// Returns the source location of the caller of this function. If that function's caller is /// annotated then its call location will be returned, and so on up the stack to the first call From c84246633e32f71095b6584258700513ae290f7c Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Tue, 10 Jun 2025 01:37:47 +0000 Subject: [PATCH 14/42] Update dependencies in `library/Cargo.lock` This removes the `compiler_builtins` dependency from a handful of library dependencies, which is progress toward [1]. [1]: https://github.com/rust-lang/rust/issues/142265 --- Cargo.lock | 54 ++++++++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 966ae72dc2ad1..abdc0592d43f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,11 +16,10 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -51,11 +50,10 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -81,12 +79,11 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7" +checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-core", "windows-sys", @@ -104,9 +101,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", @@ -126,22 +123,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -157,22 +152,20 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -274,11 +267,10 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -381,11 +373,10 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", "rustc-std-workspace-std", ] @@ -414,11 +405,10 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] From 743d0054cd9f6bcf8e28761723950c8c96fc6343 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Tue, 10 Jun 2025 18:25:21 +0000 Subject: [PATCH 15/42] Upgrade the standard library `object` version 0.37.0 is a semver-breaking release but the only breakage is in `elf::R_RISCV_GNU_*` and `pe::IMAGE_WEAK_EXTERN_*` constants, as well as Mach-O dyld. This API is not used by `std`, so we should be fine to upgrade. This new version also includes functionality for parsing Wasm object files that we may eventually like to make use of. Also includes the minor bump from 0.37.0 to 0.37.1 to help [1]. Changelog: https://github.com/gimli-rs/object/blob/master/CHANGELOG.md#0370 [1]: https://github.com/rust-lang/rust/issues/142265 --- Cargo.lock | 10 ++++------ std/Cargo.toml | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 966ae72dc2ad1..f0a7f6874ba28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,11 +157,10 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -179,11 +178,10 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" dependencies = [ - "compiler_builtins", "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", diff --git a/std/Cargo.toml b/std/Cargo.toml index 53d78dcc48847..3e2f34cfb3726 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -40,7 +40,7 @@ libc = { version = "0.2.172", default-features = false, features = [ ], public = true } [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'elf', 'macho', @@ -50,7 +50,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur ] } [target.'cfg(target_os = "aix")'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'xcoff', 'unaligned', From b8e0586b2e0337eed5ccfde4bf34a65b38e9e978 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Tue, 10 Jun 2025 18:25:21 +0000 Subject: [PATCH 16/42] Upgrade the standard library `addr2line` version 0.25.0 is a breaking change only because it upgrades the `gimli` version. It also includes a change to the `compiler-builtins` dependency that helps with [1]. Changelog: https://github.com/gimli-rs/addr2line/blob/master/CHANGELOG.md#0250-20250611 [1]: https://github.com/rust-lang/rust/issues/142265 --- Cargo.lock | 19 ++++++++++++++----- std/Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0a7f6874ba28..85c0e781d1fce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,12 +4,11 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ - "compiler_builtins", - "gimli", + "gimli 0.32.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -124,6 +123,16 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "gimli" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +dependencies = [ + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + [[package]] name = "hashbrown" version = "0.15.3" @@ -406,7 +415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.31.1", "rustc-std-workspace-core", ] diff --git a/std/Cargo.toml b/std/Cargo.toml index 3e2f34cfb3726..ae7107938f363 100644 --- a/std/Cargo.toml +++ b/std/Cargo.toml @@ -32,7 +32,7 @@ rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.8.0", optional = true, default-features = false } -addr2line = { version = "0.24.0", optional = true, default-features = false } +addr2line = { version = "0.25.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.172", default-features = false, features = [ From 9901c634fae169b363400a5a8528e6e38ae4e116 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Wed, 11 Jun 2025 20:05:06 +0000 Subject: [PATCH 17/42] Upgrade the standard library `unwinding` version This comes with a `gimli` upgrade, so we no longer have two different versions. --- Cargo.lock | 19 ++++--------------- unwind/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85c0e781d1fce..b6ef2126b44e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ - "gimli 0.32.0", + "gimli", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -112,17 +112,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "gimli" version = "0.32.0" @@ -410,12 +399,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" +checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751" dependencies = [ "compiler_builtins", - "gimli 0.31.1", + "gimli", "rustc-std-workspace-core", ] diff --git a/unwind/Cargo.toml b/unwind/Cargo.toml index ad373420a96f8..f8da09f71931a 100644 --- a/unwind/Cargo.toml +++ b/unwind/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.7", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features] From fcb45d0fe06d329af91f232dfbd5ca4dd57789c0 Mon Sep 17 00:00:00 2001 From: Jeremy Smart <jeremy3141592@gmail.com> Date: Wed, 11 Jun 2025 22:57:57 -0400 Subject: [PATCH 18/42] update docs, test --- alloc/src/vec/mod.rs | 6 +----- alloctests/tests/vec.rs | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/alloc/src/vec/mod.rs b/alloc/src/vec/mod.rs index 96d082aba223d..5bd82560da7ed 100644 --- a/alloc/src/vec/mod.rs +++ b/alloc/src/vec/mod.rs @@ -735,13 +735,9 @@ impl<T> Vec<T> { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } - /// Returns a mutable reference to the greatest item in the binary heap, or + /// Returns a mutable reference to the last item in the vector, or /// `None` if it is empty. /// - /// Note: If the `PeekMut` value is leaked, some heap elements might get - /// leaked along with it, but the remaining elements will remain a valid - /// heap. - /// /// # Examples /// /// Basic usage: diff --git a/alloctests/tests/vec.rs b/alloctests/tests/vec.rs index adbd4ccb8972a..51b49b8edb3f0 100644 --- a/alloctests/tests/vec.rs +++ b/alloctests/tests/vec.rs @@ -2708,6 +2708,8 @@ fn test_peek_mut() { assert_eq!(*p, 2); *p = 0; assert_eq!(*p, 0); + p.pop(); + assert_eq!(vec.len(), 1); } else { unreachable!() } From 8c8ed8f82b5a4ac1526b345a65099a745eb91a0e Mon Sep 17 00:00:00 2001 From: Urgau <urgau@numericable.fr> Date: Thu, 19 Dec 2024 22:33:49 +0100 Subject: [PATCH 19/42] Allow `unpredictable_function_pointer_comparisons` lint in more places --- core/src/task/wake.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/task/wake.rs b/core/src/task/wake.rs index 9b8fefe42af60..bb7efe582f7a3 100644 --- a/core/src/task/wake.rs +++ b/core/src/task/wake.rs @@ -104,6 +104,7 @@ impl RawWaker { /// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot /// be sent across threads. #[stable(feature = "futures_api", since = "1.36.0")] +#[allow(unpredictable_function_pointer_comparisons)] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { /// This function will be called when the [`RawWaker`] gets cloned, e.g. when From fd45ff2da182168df30b1ad8fc9126c5b7a57a58 Mon Sep 17 00:00:00 2001 From: Shun Sakai <sorairolake@protonmail.ch> Date: Thu, 12 Jun 2025 16:29:09 +0900 Subject: [PATCH 20/42] chore(doctest): Remove redundant blank lines --- core/src/num/int_macros.rs | 1 - core/src/num/mod.rs | 1 - core/src/slice/ascii.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/core/src/num/int_macros.rs b/core/src/num/int_macros.rs index 65560f63c1859..3a7bc902f93cd 100644 --- a/core/src/num/int_macros.rs +++ b/core/src/num/int_macros.rs @@ -239,7 +239,6 @@ macro_rules! int_impl { /// Basic usage: /// /// ``` - /// #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")] diff --git a/core/src/num/mod.rs b/core/src/num/mod.rs index 5c73bddbef2d1..ab2fcff61cd12 100644 --- a/core/src/num/mod.rs +++ b/core/src/num/mod.rs @@ -1053,7 +1053,6 @@ impl u8 { /// # Examples /// /// ``` - /// /// assert_eq!("0", b'0'.escape_ascii().to_string()); /// assert_eq!("\\t", b'\t'.escape_ascii().to_string()); /// assert_eq!("\\r", b'\r'.escape_ascii().to_string()); diff --git a/core/src/slice/ascii.rs b/core/src/slice/ascii.rs index d91f8bba548fc..b4d9a1b1ca4fd 100644 --- a/core/src/slice/ascii.rs +++ b/core/src/slice/ascii.rs @@ -128,7 +128,6 @@ impl [u8] { /// # Examples /// /// ``` - /// /// let s = b"0\t\r\n'\"\\\x9d"; /// let escaped = s.escape_ascii().to_string(); /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d"); From e51e83bd9b82ceeb7ffd7b5fcd05e516e9f12f6a Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Tue, 10 Jun 2025 00:25:51 +0000 Subject: [PATCH 21/42] Update the stdarch submodule Includes the following changes: * Add s390x z17 target features [1] * Remove `compiler-builtins` from `rustc-dep-of-std` dependencies [2] * Darwin AArch64 detection update [3] * Fixes for the latest nightly [4] * Add a lockfile [5] [1]: https://github.com/rust-lang/stdarch/pull/1826 [2]: https://github.com/rust-lang/stdarch/pull/1825 [3]: https://github.com/rust-lang/stdarch/pull/1827 [4]: https://github.com/rust-lang/stdarch/pull/1830 [5]: https://github.com/rust-lang/stdarch/pull/1829 --- Cargo.lock | 1 - stdarch | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 966ae72dc2ad1..8e39e7a09f42b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,7 +353,6 @@ name = "std_detect" version = "0.1.5" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-alloc", "rustc-std-workspace-core", diff --git a/stdarch b/stdarch index 5c1c436524c0b..1b4d15df12079 160000 --- a/stdarch +++ b/stdarch @@ -1 +1 @@ -Subproject commit 5c1c436524c0bbc8db83577f42f8bea9006a7b75 +Subproject commit 1b4d15df12079504942d0a3f1030b2039b8a776c From 05269b7e6c583331f8dbbf79dfeaaeab6f445273 Mon Sep 17 00:00:00 2001 From: xizheyin <xizheyin@smail.nju.edu.cn> Date: Sat, 7 Jun 2025 18:57:33 +0800 Subject: [PATCH 22/42] Tracking the old name of renamed unstable library attribute Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn> --- core/src/ops/control_flow.rs | 4 ++-- core/src/ops/mod.rs | 2 +- core/src/ops/try_trait.rs | 14 +++++++------- core/src/option.rs | 4 ++-- core/src/result.rs | 4 ++-- core/src/task/poll.rs | 8 ++++---- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/src/ops/control_flow.rs b/core/src/ops/control_flow.rs index ef7e6f9c2f491..26661b20c12d6 100644 --- a/core/src/ops/control_flow.rs +++ b/core/src/ops/control_flow.rs @@ -98,7 +98,7 @@ pub enum ControlFlow<B, C = ()> { // is a no-op conversion in the `Try` implementation. } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<B, C> ops::Try for ControlFlow<B, C> { type Output = C; type Residual = ControlFlow<B, convert::Infallible>; @@ -117,7 +117,7 @@ impl<B, C> ops::Try for ControlFlow<B, C> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> { diff --git a/core/src/ops/mod.rs b/core/src/ops/mod.rs index 1658f0e5a3692..87dd873fdb57d 100644 --- a/core/src/ops/mod.rs +++ b/core/src/ops/mod.rs @@ -194,7 +194,7 @@ pub use self::try_trait::Residual; #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] pub use self::try_trait::Yeet; pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] pub use self::try_trait::{FromResidual, Try}; #[unstable(feature = "coerce_unsized", issue = "18598")] pub use self::unsize::CoerceUnsized; diff --git a/core/src/ops/try_trait.rs b/core/src/ops/try_trait.rs index bac8ffb074ba8..aebbddb4f1c07 100644 --- a/core/src/ops/try_trait.rs +++ b/core/src/ops/try_trait.rs @@ -112,7 +112,7 @@ use crate::ops::ControlFlow; /// R::from_output(accum) /// } /// ``` -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_on_unimplemented( on( all(from_desugaring = "TryBlock"), @@ -130,7 +130,7 @@ use crate::ops::ControlFlow; #[lang = "Try"] pub trait Try: FromResidual { /// The type of the value produced by `?` when *not* short-circuiting. - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Output; /// The type of the value passed to [`FromResidual::from_residual`] @@ -154,7 +154,7 @@ pub trait Try: FromResidual { /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual` /// type: that type will have a "hole" in the correct place, and will maintain the /// "foo-ness" of the residual so other types need to opt-in to interconversion. - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Residual; /// Constructs the type from its `Output` type. @@ -186,7 +186,7 @@ pub trait Try: FromResidual { /// assert_eq!(r, Some(4)); /// ``` #[lang = "from_output"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn from_output(output: Self::Output) -> Self; /// Used in `?` to decide whether the operator should produce a value @@ -213,7 +213,7 @@ pub trait Try: FromResidual { /// ); /// ``` #[lang = "branch"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; } @@ -303,7 +303,7 @@ pub trait Try: FromResidual { ), )] #[rustc_diagnostic_item = "FromResidual"] -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] pub trait FromResidual<R = <Self as Try>::Residual> { /// Constructs the type from a compatible `Residual` type. /// @@ -326,7 +326,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// ); /// ``` #[lang = "from_residual"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn from_residual(residual: R) -> Self; } diff --git a/core/src/option.rs b/core/src/option.rs index 675556b07a838..4a055fd2e808f 100644 --- a/core/src/option.rs +++ b/core/src/option.rs @@ -2532,7 +2532,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T> ops::Try for Option<T> { type Output = T; type Residual = Option<convert::Infallible>; @@ -2551,7 +2551,7 @@ impl<T> ops::Try for Option<T> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> { diff --git a/core/src/result.rs b/core/src/result.rs index 23e32c2e0f01d..3a84ea66ad4b2 100644 --- a/core/src/result.rs +++ b/core/src/result.rs @@ -2051,7 +2051,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Result<T, E> { type Output = T; type Residual = Result<convert::Infallible, E>; @@ -2070,7 +2070,7 @@ impl<T, E> ops::Try for Result<T, E> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> { #[inline] #[track_caller] diff --git a/core/src/task/poll.rs b/core/src/task/poll.rs index 6aab22177ab9d..ca668361ef63b 100644 --- a/core/src/task/poll.rs +++ b/core/src/task/poll.rs @@ -229,7 +229,7 @@ impl<T> From<T> for Poll<T> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Poll<Result<T, E>> { type Output = Poll<T>; type Residual = Result<convert::Infallible, E>; @@ -249,7 +249,7 @@ impl<T, E> ops::Try for Poll<Result<T, E>> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> { #[inline] fn from_residual(x: Result<convert::Infallible, E>) -> Self { @@ -259,7 +259,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Poll<Option<Result<T, E>>> { type Output = Poll<Option<T>>; type Residual = Result<convert::Infallible, E>; @@ -280,7 +280,7 @@ impl<T, E> ops::Try for Poll<Option<Result<T, E>>> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Option<Result<T, F>>> { From 0cc8ed79a5004e01ec0b552089d94736a1eb2aa3 Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Thu, 12 Jun 2025 13:44:19 +0200 Subject: [PATCH 23/42] intrinsics: rename min_align_of to align_of --- core/src/intrinsics/mod.rs | 13 +++++-------- core/src/mem/mod.rs | 15 +++++---------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 4434ceb49bca8..7ba48cc72683c 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -926,8 +926,7 @@ pub const unsafe fn slice_get_unchecked< pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with -/// a size of `count` * `size_of::<T>()` and an alignment of -/// `min_align_of::<T>()` +/// a size of `count` * `size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// This intrinsic does not have a stable counterpart. /// # Safety @@ -941,8 +940,7 @@ pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; #[rustc_nounwind] pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with -/// a size of `count * size_of::<T>()` and an alignment of -/// `min_align_of::<T>()` +/// a size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// The volatile parameter is set to `true`, so it will not be optimized out /// unless size is equal to zero. @@ -952,8 +950,7 @@ pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, #[rustc_nounwind] pub unsafe fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a -/// size of `count * size_of::<T>()` and an alignment of -/// `min_align_of::<T>()`. +/// size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// This intrinsic does not have a stable counterpart. /// # Safety @@ -2649,7 +2646,7 @@ pub const fn size_of<T>() -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn min_align_of<T>() -> usize; +pub const fn align_of<T>() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. @@ -2689,7 +2686,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] -pub const unsafe fn min_align_of_val<T: ?Sized>(ptr: *const T) -> usize; +pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize; /// Gets a static string slice containing the name of a type. /// diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 0a5f3ee35b105..6819face4c219 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -412,7 +412,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize { #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")] pub fn min_align_of<T>() -> usize { - intrinsics::min_align_of::<T>() + intrinsics::align_of::<T>() } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -436,7 +436,7 @@ pub fn min_align_of<T>() -> usize { #[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")] pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns the [ABI]-required minimum alignment of a type in bytes. @@ -458,7 +458,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { #[rustc_promotable] #[rustc_const_stable(feature = "const_align_of", since = "1.24.0")] pub const fn align_of<T>() -> usize { - intrinsics::min_align_of::<T>() + intrinsics::align_of::<T>() } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -477,10 +477,9 @@ pub const fn align_of<T>() -> usize { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")] -#[allow(deprecated)] pub const fn align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -527,7 +526,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize { #[unstable(feature = "layout_for_ptr", issue = "69835")] pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize { // SAFETY: the caller must provide a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns `true` if dropping values of type `T` matters. @@ -637,8 +636,6 @@ pub const fn needs_drop<T: ?Sized>() -> bool { #[inline(always)] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] #[track_caller] #[rustc_const_stable(feature = "const_mem_zeroed", since = "1.75.0")] @@ -677,8 +674,6 @@ pub const unsafe fn zeroed<T>() -> T { #[must_use] #[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] #[track_caller] pub unsafe fn uninitialized<T>() -> T { From d3044056b335fe4bda7c4447294611a11877d9dc Mon Sep 17 00:00:00 2001 From: Tamir Duberstein <tamird@gmail.com> Date: Fri, 18 Apr 2025 11:18:25 -0400 Subject: [PATCH 24/42] Delegate `<CStr as Debug>` to `ByteStr` This allows UTF-8 characters to be printed without escapes, rather than just ASCII. --- alloc/src/ffi/c_str.rs | 2 ++ core/src/ffi/c_str.rs | 4 +++- coretests/tests/ffi/cstr.rs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/alloc/src/ffi/c_str.rs b/alloc/src/ffi/c_str.rs index 8b448a18402c3..48849bf7536c0 100644 --- a/alloc/src/ffi/c_str.rs +++ b/alloc/src/ffi/c_str.rs @@ -714,6 +714,8 @@ impl ops::Deref for CString { } } +/// Delegates to the [`CStr`] implementation of [`fmt::Debug`], +/// showing invalid UTF-8 as hex escapes. #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/core/src/ffi/c_str.rs b/core/src/ffi/c_str.rs index 595cc1fe025ec..f7a21072f5393 100644 --- a/core/src/ffi/c_str.rs +++ b/core/src/ffi/c_str.rs @@ -162,10 +162,12 @@ impl fmt::Display for FromBytesUntilNulError { } } +/// Shows the underlying bytes as a normal string, with invalid UTF-8 +/// presented as hex escape sequences. #[stable(feature = "cstr_debug", since = "1.3.0")] impl fmt::Debug for CStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\"", self.to_bytes().escape_ascii()) + fmt::Debug::fmt(crate::bstr::ByteStr::from_bytes(self.to_bytes()), f) } } diff --git a/coretests/tests/ffi/cstr.rs b/coretests/tests/ffi/cstr.rs index dc34240cd99d2..7d669cc1c3fff 100644 --- a/coretests/tests/ffi/cstr.rs +++ b/coretests/tests/ffi/cstr.rs @@ -17,7 +17,7 @@ fn compares_as_u8s() { #[test] fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; - assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); + assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n…\xff""#); } #[test] From 83376b40af02837180b5580d8fc3be6adf8ac780 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein <tamird@gmail.com> Date: Sat, 24 May 2025 07:44:31 -0400 Subject: [PATCH 25/42] Delegate `<SocketAddr as Debug>` to `ByteStr` This allows UTF-8 characters to be printed without escapes, rather than just ASCII. --- std/src/os/unix/net/addr.rs | 9 +++++---- std/src/os/unix/net/tests.rs | 9 +++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/std/src/os/unix/net/addr.rs b/std/src/os/unix/net/addr.rs index cb1246db3109e..fd6fe72dd248b 100644 --- a/std/src/os/unix/net/addr.rs +++ b/std/src/os/unix/net/addr.rs @@ -1,3 +1,4 @@ +use crate::bstr::ByteStr; use crate::ffi::OsStr; #[cfg(any(doc, target_os = "android", target_os = "linux"))] use crate::os::net::linux_ext; @@ -61,7 +62,7 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s enum AddressKind<'a> { Unnamed, Pathname(&'a Path), - Abstract(&'a [u8]), + Abstract(&'a ByteStr), } /// An address associated with a Unix socket. @@ -245,7 +246,7 @@ impl SocketAddr { { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) + AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) } else { AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) } @@ -260,7 +261,7 @@ impl Sealed for SocketAddr {} #[stable(feature = "unix_socket_abstract", since = "1.70.0")] impl linux_ext::addr::SocketAddrExt for SocketAddr { fn as_abstract_name(&self) -> Option<&[u8]> { - if let AddressKind::Abstract(name) = self.address() { Some(name) } else { None } + if let AddressKind::Abstract(name) = self.address() { Some(name.as_bytes()) } else { None } } fn from_abstract_name<N>(name: N) -> crate::io::Result<Self> @@ -295,7 +296,7 @@ impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.address() { AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "\"{}\" (abstract)", name.escape_ascii()), + AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"), AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"), } } diff --git a/std/src/os/unix/net/tests.rs b/std/src/os/unix/net/tests.rs index 0398a535eb54a..9a88687b1df0c 100644 --- a/std/src/os/unix/net/tests.rs +++ b/std/src/os/unix/net/tests.rs @@ -411,6 +411,15 @@ fn test_unix_datagram_timeout_zero_duration() { assert_eq!(err.kind(), ErrorKind::InvalidInput); } +#[cfg(any(target_os = "android", target_os = "linux"))] +#[test] +fn abstract_socket_addr_debug() { + assert_eq!( + r#""\0hello world\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff" (abstract)"#, + format!("{:?}", SocketAddr::from_abstract_name(b"\0hello world\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff").unwrap()), + ); +} + #[test] fn abstract_namespace_not_allowed_connect() { assert!(UnixStream::connect("\0asdf").is_err()); From 1b28bd02b796a9c91eb35e71213d475de5491e4b Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Fri, 13 Jun 2025 01:16:36 +0200 Subject: [PATCH 26/42] Unimplement unsized_locals --- core/src/mem/mod.rs | 28 ++++++++++++++++++++++++++-- coretests/tests/ptr.rs | 1 - 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/core/src/mem/mod.rs b/core/src/mem/mod.rs index 0a5f3ee35b105..2248099e94bbc 100644 --- a/core/src/mem/mod.rs +++ b/core/src/mem/mod.rs @@ -149,8 +149,32 @@ pub const fn forget<T>(t: T) { /// Like [`forget`], but also accepts unsized values. /// -/// This function is just a shim intended to be removed when the `unsized_locals` feature gets -/// stabilized. +/// While Rust does not permit unsized locals since its removal in [#111942] it is +/// still possible to call functions with unsized values from a function argument +/// or in-place construction. +/// +/// ```rust +/// #![feature(unsized_fn_params, forget_unsized)] +/// #![allow(internal_features)] +/// +/// use std::mem::forget_unsized; +/// +/// pub fn in_place() { +/// forget_unsized(*Box::<str>::from("str")); +/// } +/// +/// pub fn param(x: str) { +/// forget_unsized(x); +/// } +/// ``` +/// +/// This works because the compiler will alter these functions to pass the parameter +/// by reference instead. This trick is necessary to support `Box<dyn FnOnce()>: FnOnce()`. +/// See [#68304] and [#71170] for more information. +/// +/// [#111942]: https://github.com/rust-lang/rust/issues/111942 +/// [#68304]: https://github.com/rust-lang/rust/issues/68304 +/// [#71170]: https://github.com/rust-lang/rust/pull/71170 #[inline] #[unstable(feature = "forget_unsized", issue = "none")] pub fn forget_unsized<T: ?Sized>(t: T) { diff --git a/coretests/tests/ptr.rs b/coretests/tests/ptr.rs index bb60fb07468f9..197a14423b59d 100644 --- a/coretests/tests/ptr.rs +++ b/coretests/tests/ptr.rs @@ -653,7 +653,6 @@ fn thin_box() { // if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added. // * Constructing a `ThinBox` without consuming and deallocating a `Box` // requires either the unstable `Unsize` marker trait, - // or the unstable `unsized_locals` language feature, // or taking `&dyn T` and restricting to `T: Copy`. use std::alloc::*; From 34cc200eef63a3458154486fe480674c1f370226 Mon Sep 17 00:00:00 2001 From: qinghon <wushengshijie@outlook.com> Date: Fri, 13 Jun 2025 13:27:47 +0800 Subject: [PATCH 27/42] Eliminate `build.rs`-generated Aarch64 atomic macros (#951) Replace `build.rs` Rust generation with macros, using the unstable `${concat(...)}`. Fixes: https://github.com/rust-lang/compiler-builtins/issues/947 --- compiler-builtins/builtins-test/tests/lse.rs | 3 +- compiler-builtins/compiler-builtins/build.rs | 62 ---------------- .../compiler-builtins/src/aarch64_linux.rs | 74 ++++++++++++++++++- .../compiler-builtins/src/lib.rs | 1 + 4 files changed, 75 insertions(+), 65 deletions(-) diff --git a/compiler-builtins/builtins-test/tests/lse.rs b/compiler-builtins/builtins-test/tests/lse.rs index 53167d98fc0e3..0d85228d7a22d 100644 --- a/compiler-builtins/builtins-test/tests/lse.rs +++ b/compiler-builtins/builtins-test/tests/lse.rs @@ -1,4 +1,5 @@ #![feature(decl_macro)] // so we can use pub(super) +#![feature(macro_metavar_expr_concat)] #![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))] /// Translate a byte size to a Rust type. @@ -87,7 +88,7 @@ test_op!(add, |left, right| left.wrapping_add(right)); test_op!(clr, |left, right| left & !right); test_op!(xor, std::ops::BitXor::bitxor); test_op!(or, std::ops::BitOr::bitor); - +use compiler_builtins::{foreach_bytes, foreach_ordering}; compiler_builtins::foreach_cas!(cas::test); compiler_builtins::foreach_cas16!(test_cas16); compiler_builtins::foreach_swp!(swap::test); diff --git a/compiler-builtins/compiler-builtins/build.rs b/compiler-builtins/compiler-builtins/build.rs index d37fdc5df507a..e909a0dcb97e5 100644 --- a/compiler-builtins/compiler-builtins/build.rs +++ b/compiler-builtins/compiler-builtins/build.rs @@ -1,9 +1,6 @@ mod configure; -use std::collections::BTreeMap; use std::env; -use std::path::PathBuf; -use std::sync::atomic::Ordering; use configure::{Target, configure_aliases, configure_f16_f128}; @@ -85,10 +82,6 @@ fn main() { { println!("cargo:rustc-cfg=kernel_user_helpers") } - - if llvm_target[0].starts_with("aarch64") { - generate_aarch64_outlined_atomics(); - } } /// Run configuration for `libm` since it is included directly. @@ -131,61 +124,6 @@ fn configure_libm(target: &Target) { println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); } -fn aarch64_symbol(ordering: Ordering) -> &'static str { - match ordering { - Ordering::Relaxed => "relax", - Ordering::Acquire => "acq", - Ordering::Release => "rel", - Ordering::AcqRel => "acq_rel", - _ => panic!("unknown symbol for {ordering:?}"), - } -} - -/// The `concat_idents` macro is extremely annoying and doesn't allow us to define new items. -/// Define them from the build script instead. -/// Note that the majority of the code is still defined in `aarch64.rs` through inline macros. -fn generate_aarch64_outlined_atomics() { - use std::fmt::Write; - // #[macro_export] so that we can use this in tests - let gen_macro = - |name| format!("#[macro_export] macro_rules! foreach_{name} {{ ($macro:path) => {{\n"); - - // Generate different macros for add/clr/eor/set so that we can test them separately. - let sym_names = ["cas", "ldadd", "ldclr", "ldeor", "ldset", "swp"]; - let mut macros = BTreeMap::new(); - for sym in sym_names { - macros.insert(sym, gen_macro(sym)); - } - - // Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. - let mut cas16 = gen_macro("cas16"); - - for ordering in [ - Ordering::Relaxed, - Ordering::Acquire, - Ordering::Release, - Ordering::AcqRel, - ] { - let sym_ordering = aarch64_symbol(ordering); - for size in [1, 2, 4, 8] { - for (sym, macro_) in &mut macros { - let name = format!("__aarch64_{sym}{size}_{sym_ordering}"); - writeln!(macro_, "$macro!( {ordering:?}, {size}, {name} );").unwrap(); - } - } - let name = format!("__aarch64_cas16_{sym_ordering}"); - writeln!(cas16, "$macro!( {ordering:?}, {name} );").unwrap(); - } - - let mut buf = String::new(); - for macro_def in macros.values().chain(std::iter::once(&cas16)) { - buf += macro_def; - buf += "}; }\n"; - } - let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - std::fs::write(out_dir.join("outlined_atomics.rs"), buf).unwrap(); -} - /// Emit directives for features we expect to support that aren't in `Cargo.toml`. /// /// These are mostly cfg elements emitted by this `build.rs`. diff --git a/compiler-builtins/compiler-builtins/src/aarch64_linux.rs b/compiler-builtins/compiler-builtins/src/aarch64_linux.rs index e238d0237eb31..2402a3fe1e62a 100644 --- a/compiler-builtins/compiler-builtins/src/aarch64_linux.rs +++ b/compiler-builtins/compiler-builtins/src/aarch64_linux.rs @@ -262,8 +262,78 @@ macro_rules! or { }; } -// See `generate_aarch64_outlined_atomics` in build.rs. -include!(concat!(env!("OUT_DIR"), "/outlined_atomics.rs")); +#[macro_export] +macro_rules! foreach_ordering { + ($macro:path, $bytes:tt, $name:ident) => { + $macro!( Relaxed, $bytes, ${concat($name, _relax)} ); + $macro!( Acquire, $bytes, ${concat($name, _acq)} ); + $macro!( Release, $bytes, ${concat($name, _rel)} ); + $macro!( AcqRel, $bytes, ${concat($name, _acq_rel)} ); + }; + ($macro:path, $name:ident) => { + $macro!( Relaxed, ${concat($name, _relax)} ); + $macro!( Acquire, ${concat($name, _acq)} ); + $macro!( Release, ${concat($name, _rel)} ); + $macro!( AcqRel, ${concat($name, _acq_rel)} ); + }; +} + +#[macro_export] +macro_rules! foreach_bytes { + ($macro:path, $name:ident) => { + foreach_ordering!( $macro, 1, ${concat(__aarch64_, $name, "1")} ); + foreach_ordering!( $macro, 2, ${concat(__aarch64_, $name, "2")} ); + foreach_ordering!( $macro, 4, ${concat(__aarch64_, $name, "4")} ); + foreach_ordering!( $macro, 8, ${concat(__aarch64_, $name, "8")} ); + }; +} + +/// Generate different macros for cas/swp/add/clr/eor/set so that we can test them separately. +#[macro_export] +macro_rules! foreach_cas { + ($macro:path) => { + foreach_bytes!($macro, cas); + }; +} + +/// Only CAS supports 16 bytes, and it has a different implementation that uses a different macro. +#[macro_export] +macro_rules! foreach_cas16 { + ($macro:path) => { + foreach_ordering!($macro, __aarch64_cas16); + }; +} +#[macro_export] +macro_rules! foreach_swp { + ($macro:path) => { + foreach_bytes!($macro, swp); + }; +} +#[macro_export] +macro_rules! foreach_ldadd { + ($macro:path) => { + foreach_bytes!($macro, ldadd); + }; +} +#[macro_export] +macro_rules! foreach_ldclr { + ($macro:path) => { + foreach_bytes!($macro, ldclr); + }; +} +#[macro_export] +macro_rules! foreach_ldeor { + ($macro:path) => { + foreach_bytes!($macro, ldeor); + }; +} +#[macro_export] +macro_rules! foreach_ldset { + ($macro:path) => { + foreach_bytes!($macro, ldset); + }; +} + foreach_cas!(compare_and_swap); foreach_cas16!(compare_and_swap_i128); foreach_swp!(swap); diff --git a/compiler-builtins/compiler-builtins/src/lib.rs b/compiler-builtins/compiler-builtins/src/lib.rs index 6a6b28067e8c8..ef3299d6967cf 100644 --- a/compiler-builtins/compiler-builtins/src/lib.rs +++ b/compiler-builtins/compiler-builtins/src/lib.rs @@ -8,6 +8,7 @@ #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] +#![feature(macro_metavar_expr_concat)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] From 3ab6f9e106c503690bf6790f6583eac9cc22b3e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Fri, 13 Jun 2025 08:19:17 +0200 Subject: [PATCH 28/42] tweak runtime/const macro management --- coretests/tests/floats/mod.rs | 93 ++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index 8f15a2625af07..6b4f586fa9b6b 100644 --- a/coretests/tests/floats/mod.rs +++ b/coretests/tests/floats/mod.rs @@ -24,9 +24,11 @@ const fn lim_for_ty<T: Approx + Copy>(_x: T) -> T { T::LIM } +// We have runtime ("rt") and const versions of these macros. + /// Verify that floats are within a tolerance of each other. -macro_rules! assert_approx_eq_ { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; +macro_rules! assert_approx_eq_rt { + ($a:expr, $b:expr) => {{ assert_approx_eq_rt!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -37,11 +39,18 @@ macro_rules! assert_approx_eq_ { ); }}; } -pub(crate) use assert_approx_eq_ as assert_approx_eq; +macro_rules! assert_approx_eq_const { + ($a:expr, $b:expr) => {{ assert_approx_eq_const!($a, $b, $crate::floats::lim_for_ty($a)) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!(diff <= $lim); + }}; +} /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq_ { +macro_rules! assert_biteq_rt { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ let l = $left; let r = $right; @@ -69,54 +78,45 @@ macro_rules! assert_biteq_ { } }}; ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq_!(@inner $left, $right, "\n", $($tt)*) + assert_biteq_rt!(@inner $left, $right, "\n", $($tt)*) }; ($left:expr, $right:expr $(,)?) => { - assert_biteq_!(@inner $left, $right, "", "") + assert_biteq_rt!(@inner $left, $right, "", "") }; } -pub(crate) use assert_biteq_ as assert_biteq; +macro_rules! assert_biteq_const { + (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ + let l = $left; + let r = $right; -mod const_asserts { - // Shadow some assert implementations that would otherwise not compile in a const-context. - // Every macro added here also needs to be added in the `float_test!` macro below. + // Hack to coerce left and right to the same type + let mut _eq_ty = l; + _eq_ty = r; - macro_rules! assert_biteq { - (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ - let l = $left; - let r = $right; + assert!(l.to_bits() == r.to_bits()); - // Hack to coerce left and right to the same type - let mut _eq_ty = l; - _eq_ty = r; + if !l.is_nan() && !r.is_nan() { + // Also check that standard equality holds, since most tests use `assert_biteq` rather + // than `assert_eq`. + assert!(l == r); + } + }}; + ($left:expr, $right:expr , $($tt:tt)*) => { + assert_biteq_const!(@inner $left, $right, "\n", $($tt)*) + }; + ($left:expr, $right:expr $(,)?) => { + assert_biteq_const!(@inner $left, $right, "", "") + }; +} - assert!(l.to_bits() == r.to_bits()); +// Use the runtime version by default. +// This way, they can be shadowed by the const versions. +pub(crate) use {assert_approx_eq_rt as assert_approx_eq, assert_biteq_rt as assert_biteq}; - if !l.is_nan() && !r.is_nan() { - // Also check that standard equality holds, since most tests use `assert_biteq` rather - // than `assert_eq`. - assert!(l == r); - } - }}; - ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq!(@inner $left, $right, "\n", $($tt)*) - }; - ($left:expr, $right:expr $(,)?) => { - assert_biteq!(@inner $left, $right, "", "") - }; - } - pub(crate) use assert_biteq; - - macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; - ($a:expr, $b:expr, $lim:expr) => {{ - let (a, b) = (&$a, &$b); - let diff = (*a - *b).abs(); - assert!(diff <= $lim); - }}; - } - pub(crate) use assert_approx_eq; -} +// Also make the const version available for re-exports. +#[rustfmt::skip] +pub(crate) use assert_biteq_const; +pub(crate) use assert_approx_eq_const; /// Generate float tests for all our float types, for compile-time and run-time behavior. /// @@ -135,6 +135,7 @@ mod const_asserts { /// /* write tests here, using `Float` as the type */ /// } /// } +/// ``` macro_rules! float_test { ( name: $name:ident, @@ -186,8 +187,12 @@ macro_rules! float_test { mod const_ { #[allow(unused)] use super::Approx; + // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] - use $crate::floats::const_asserts::{assert_biteq, assert_approx_eq}; + use $crate::floats::{ + assert_approx_eq_const as assert_approx_eq, + assert_biteq_const as assert_biteq, + }; #[test] $( $( #[$f16_const_meta] )+ )? From f3f87172e9316df3b716288832e1f41086108b7b Mon Sep 17 00:00:00 2001 From: Chris Denton <chris@chrisdenton.dev> Date: Fri, 13 Jun 2025 09:14:15 +0000 Subject: [PATCH 29/42] Remove "intermittent" wording from `ReadDir` --- std/src/fs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 6cbf8301e01b9..0cd794fd3efbb 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -153,9 +153,8 @@ pub struct Metadata(fs_imp::FileAttr); /// dependent. /// /// # Errors -/// -/// This [`io::Result`] will be an [`Err`] if there's some sort of intermittent -/// IO error during iteration. +/// This [`io::Result`] will be an [`Err`] if an error occurred while fetching +/// the next entry from the OS. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct ReadDir(fs_imp::ReadDir); From cd551066dc58cf26b802a41230fb959b148320b3 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot <sasha.pourcelot@protonmail.com> Date: Fri, 13 Jun 2025 12:47:53 +0200 Subject: [PATCH 30/42] doc: mention that intrinsics should not be called in user code Intrinsic functions declared in `std::intrinsics` are an implementation detail and should not be called directly by the user. The compiler explicitly warns against their use in user code: ``` warning: the feature `core_intrinsics` is internal to the compiler or standard library --> src/lib.rs:1:12 | 1 | #![feature(core_intrinsics)] | ^^^^^^^^^^^^^^^ | = note: using it is strongly discouraged = note: `#[warn(internal_features)]` on by default ``` [**Playground link**] This PR documents what the compiler warning says: these intrinsics should not be called outside the standard library. [**Playground link**]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=1c893b0698291f550bbdde0151fd221b --- core/src/intrinsics/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/intrinsics/mod.rs b/core/src/intrinsics/mod.rs index 4434ceb49bca8..d8c3d056b1c73 100644 --- a/core/src/intrinsics/mod.rs +++ b/core/src/intrinsics/mod.rs @@ -1,5 +1,9 @@ //! Compiler intrinsics. //! +//! The functions in this module are implementation details of `core` and should +//! not be used outside of the standard library. We generally provide access to +//! intrinsics via stable wrapper functions. Use these instead. +//! //! These are the imports making intrinsics available to Rust code. The actual implementations live in the compiler. //! Some of these intrinsics are lowered to MIR in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_transform/src/lower_intrinsics.rs>. //! The remaining intrinsics are implemented for the LLVM backend in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs> From 654284e3c874c2d9f89078583e409c97a330e245 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Mon, 2 Jun 2025 17:20:22 +0000 Subject: [PATCH 31/42] fmaximum,fminimum: Fix incorrect result and add tests After adding tests, the current implementation for fminimum fails when provided a negative zero and NaN as inputs: ---- math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f64 stdout ---- thread 'math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f64' panicked at libm/src/math/fminimum_fmaximum_num.rs:240:13: fmaximum_num(-0x0p+0, NaN) l: NaN (0x7ff8000000000000) r: -0.0 (0x8000000000000000) ---- math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f32 stdout ---- thread 'math::fminimum_fmaximum_num::tests::fmaximum_num_spec_tests_f32' panicked at libm/src/math/fminimum_fmaximum_num.rs:240:13: fmaximum_num(-0x0p+0, NaN) l: NaN (0x7fc00000) r: -0.0 (0x80000000) Add more thorough spec tests for these functions and correct the implementations. Canonicalization is also moved to a trait method to centralize documentation about what it does and doesn't do. --- compiler-builtins/libm/src/math/fmin_fmax.rs | 122 +++++++++++++++- .../libm/src/math/fminimum_fmaximum.rs | 126 ++++++++++++++-- .../libm/src/math/fminimum_fmaximum_num.rs | 138 ++++++++++++++++-- .../libm/src/math/generic/fmax.rs | 3 +- .../libm/src/math/generic/fmaximum.rs | 5 +- .../libm/src/math/generic/fmaximum_num.rs | 17 ++- .../libm/src/math/generic/fmin.rs | 3 +- .../libm/src/math/generic/fminimum.rs | 5 +- .../libm/src/math/generic/fminimum_num.rs | 17 ++- .../libm/src/math/support/float_traits.rs | 9 ++ .../libm/src/math/support/macros.rs | 4 +- 11 files changed, 392 insertions(+), 57 deletions(-) diff --git a/compiler-builtins/libm/src/math/fmin_fmax.rs b/compiler-builtins/libm/src/math/fmin_fmax.rs index 2947b783e2fc5..481301994e991 100644 --- a/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -82,22 +82,77 @@ mod tests { fn fmin_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::ZERO, F::INFINITY, F::ZERO), + (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ZERO, F::INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::NEG_ONE), + (F::ONE, F::INFINITY, F::ONE), + (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), + (F::NEG_ONE, F::ONE, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::ZERO), + (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::INFINITY, F::ONE, F::ONE), + (F::INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), (F::NAN, F::NAN, F::NAN), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between zeros and NaNs does not matter + assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO); + assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] @@ -125,22 +180,77 @@ mod tests { fn fmax_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), (F::ZERO, F::NEG_ONE, F::ZERO), + (F::ZERO, F::INFINITY, F::INFINITY), + (F::ZERO, F::NEG_INFINITY, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::ONE), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::INFINITY, F::INFINITY), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ONE), + (F::ONE, F::NEG_ZERO, F::ONE), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::ONE), + (F::ONE, F::INFINITY, F::INFINITY), + (F::ONE, F::NEG_INFINITY, F::ONE), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), (F::NEG_ONE, F::ZERO, F::ZERO), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ONE, F::ONE, F::ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::INFINITY), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::INFINITY), + (F::INFINITY, F::NEG_ZERO, F::INFINITY), + (F::INFINITY, F::ONE, F::INFINITY), + (F::INFINITY, F::NEG_ONE, F::INFINITY), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_INFINITY, F::ONE, F::ONE), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::NEG_INFINITY, F::INFINITY, F::INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), (F::NAN, F::NAN, F::NAN), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fmax({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between zeros and NaNs does not matter + assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO); + assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO); + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] diff --git a/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/compiler-builtins/libm/src/math/fminimum_fmaximum.rs index b7999e27392b1..8f1308670511a 100644 --- a/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ b/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -74,24 +74,77 @@ mod tests { fn fminimum_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::ZERO, F::INFINITY, F::ZERO), + (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ZERO, F::NAN, F::NAN), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ZERO, F::INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ZERO, F::NAN, F::NAN), + (F::ONE, F::ZERO, F::ZERO), + (F::ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::NEG_ONE), + (F::ONE, F::INFINITY, F::ONE), + (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ONE, F::NAN, F::NAN), (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), + (F::NEG_ONE, F::ONE, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ONE, F::NAN, F::NAN), (F::INFINITY, F::ZERO, F::ZERO), + (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::INFINITY, F::ONE, F::ONE), + (F::INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::INFINITY, F::NAN, F::NAN), (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NAN), (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NEG_ZERO, F::NAN), + (F::NAN, F::ONE, F::NAN), + (F::NAN, F::NEG_ONE, F::NAN), + (F::NAN, F::INFINITY, F::NAN), + (F::NAN, F::NEG_INFINITY, F::NAN), (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fminimum({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::ONE, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan()); + assert!(f(F::INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::ONE).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan()); + assert!(f(F::NEG_NAN, F::INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] @@ -119,24 +172,77 @@ mod tests { fn fmaximum_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::NEG_ZERO, F::ZERO), (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), (F::ZERO, F::NEG_ONE, F::ZERO), + (F::ZERO, F::INFINITY, F::INFINITY), + (F::ZERO, F::NEG_INFINITY, F::ZERO), + (F::ZERO, F::NAN, F::NAN), + (F::NEG_ZERO, F::ZERO, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::ONE), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::INFINITY, F::INFINITY), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NAN, F::NAN), + (F::ONE, F::ZERO, F::ONE), + (F::ONE, F::NEG_ZERO, F::ONE), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::ONE), + (F::ONE, F::INFINITY, F::INFINITY), + (F::ONE, F::NEG_INFINITY, F::ONE), + (F::ONE, F::NAN, F::NAN), (F::NEG_ONE, F::ZERO, F::ZERO), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ONE, F::ONE, F::ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::INFINITY), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NAN, F::NAN), (F::INFINITY, F::ZERO, F::INFINITY), + (F::INFINITY, F::NEG_ZERO, F::INFINITY), + (F::INFINITY, F::ONE, F::INFINITY), + (F::INFINITY, F::NEG_ONE, F::INFINITY), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::INFINITY), + (F::INFINITY, F::NAN, F::NAN), (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_INFINITY, F::ONE, F::ONE), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::NEG_INFINITY, F::INFINITY, F::INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NAN), (F::NAN, F::ZERO, F::NAN), - (F::ZERO, F::NAN, F::NAN), + (F::NAN, F::NEG_ZERO, F::NAN), + (F::NAN, F::ONE, F::NAN), + (F::NAN, F::NEG_ONE, F::NAN), + (F::NAN, F::INFINITY, F::NAN), + (F::NAN, F::NEG_INFINITY, F::NAN), (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), ]; for (x, y, res) in cases { let val = f(x, y); assert_biteq!(val, res, "fmaximum({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan()); + assert!(f(F::ONE, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan()); + assert!(f(F::INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan()); + assert!(f(F::NEG_NAN, F::ONE).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan()); + assert!(f(F::NEG_NAN, F::INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] diff --git a/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs index 180d21f72b74c..fadf934180a05 100644 --- a/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ b/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -74,24 +74,77 @@ mod tests { fn fminimum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), (F::ZERO, F::ONE, F::ZERO), - (F::ONE, F::ZERO, F::ZERO), (F::ZERO, F::NEG_ONE, F::NEG_ONE), + (F::ZERO, F::INFINITY, F::ZERO), + (F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ZERO, F::INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ZERO), + (F::ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::NEG_ONE), + (F::ONE, F::INFINITY, F::ONE), + (F::ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), (F::NEG_ONE, F::ZERO, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE), + (F::NEG_ONE, F::ONE, F::NEG_ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::ZERO), + (F::INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::INFINITY, F::ONE, F::ONE), + (F::INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY), + (F::NEG_INFINITY, F::ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY), + (F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::NEG_ZERO), - (F::NEG_ZERO, F::ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y)); + for (x, y, expected) in cases { + let actual = f(x, y); + assert_biteq!(actual, expected, "fminimum_num({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] @@ -119,24 +172,77 @@ mod tests { fn fmaximum_num_spec_test<F: Float>(f: impl Fn(F, F) -> F) { let cases = [ (F::ZERO, F::ZERO, F::ZERO), - (F::ONE, F::ONE, F::ONE), + (F::ZERO, F::NEG_ZERO, F::ZERO), (F::ZERO, F::ONE, F::ONE), - (F::ONE, F::ZERO, F::ONE), (F::ZERO, F::NEG_ONE, F::ZERO), + (F::ZERO, F::INFINITY, F::INFINITY), + (F::ZERO, F::NEG_INFINITY, F::ZERO), + (F::ZERO, F::NAN, F::ZERO), + (F::ZERO, F::NEG_NAN, F::ZERO), + (F::NEG_ZERO, F::ZERO, F::ZERO), + (F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ZERO, F::ONE, F::ONE), + (F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO), + (F::NEG_ZERO, F::INFINITY, F::INFINITY), + (F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO), + (F::NEG_ZERO, F::NAN, F::NEG_ZERO), + (F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO), + (F::ONE, F::ZERO, F::ONE), + (F::ONE, F::NEG_ZERO, F::ONE), + (F::ONE, F::ONE, F::ONE), + (F::ONE, F::NEG_ONE, F::ONE), + (F::ONE, F::INFINITY, F::INFINITY), + (F::ONE, F::NEG_INFINITY, F::ONE), + (F::ONE, F::NAN, F::ONE), + (F::ONE, F::NEG_NAN, F::ONE), (F::NEG_ONE, F::ZERO, F::ZERO), + (F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_ONE, F::ONE, F::ONE), + (F::NEG_ONE, F::NEG_ONE, F::NEG_ONE), + (F::NEG_ONE, F::INFINITY, F::INFINITY), + (F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE), + (F::NEG_ONE, F::NAN, F::NEG_ONE), + (F::NEG_ONE, F::NEG_NAN, F::NEG_ONE), (F::INFINITY, F::ZERO, F::INFINITY), + (F::INFINITY, F::NEG_ZERO, F::INFINITY), + (F::INFINITY, F::ONE, F::INFINITY), + (F::INFINITY, F::NEG_ONE, F::INFINITY), + (F::INFINITY, F::INFINITY, F::INFINITY), + (F::INFINITY, F::NEG_INFINITY, F::INFINITY), + (F::INFINITY, F::NAN, F::INFINITY), + (F::INFINITY, F::NEG_NAN, F::INFINITY), (F::NEG_INFINITY, F::ZERO, F::ZERO), + (F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_INFINITY, F::ONE, F::ONE), + (F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE), + (F::NEG_INFINITY, F::INFINITY, F::INFINITY), + (F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NAN, F::NEG_INFINITY), + (F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY), (F::NAN, F::ZERO, F::ZERO), - (F::ZERO, F::NAN, F::ZERO), + (F::NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NAN, F::ONE, F::ONE), + (F::NAN, F::NEG_ONE, F::NEG_ONE), + (F::NAN, F::INFINITY, F::INFINITY), + (F::NAN, F::NEG_INFINITY, F::NEG_INFINITY), (F::NAN, F::NAN, F::NAN), - (F::ZERO, F::NEG_ZERO, F::ZERO), - (F::NEG_ZERO, F::ZERO, F::ZERO), + (F::NEG_NAN, F::ZERO, F::ZERO), + (F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO), + (F::NEG_NAN, F::ONE, F::ONE), + (F::NEG_NAN, F::NEG_ONE, F::NEG_ONE), + (F::NEG_NAN, F::INFINITY, F::INFINITY), + (F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY), ]; - for (x, y, res) in cases { - let val = f(x, y); - assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); + for (x, y, expected) in cases { + let actual = f(x, y); + assert_biteq!(actual, expected, "fmaximum_num({}, {})", Hexf(x), Hexf(y)); } + + // Ordering between NaNs does not matter + assert!(f(F::NAN, F::NEG_NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NAN).is_nan()); + assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan()); } #[test] diff --git a/compiler-builtins/libm/src/math/generic/fmax.rs b/compiler-builtins/libm/src/math/generic/fmax.rs index 54207e4b3285f..b05804704d03e 100644 --- a/compiler-builtins/libm/src/math/generic/fmax.rs +++ b/compiler-builtins/libm/src/math/generic/fmax.rs @@ -19,6 +19,5 @@ use crate::support::Float; #[inline] pub fn fmax<F: Float>(x: F, y: F) -> F { let res = if x.is_nan() || x < y { y } else { x }; - // Canonicalize - res * F::ONE + res.canonicalize() } diff --git a/compiler-builtins/libm/src/math/generic/fmaximum.rs b/compiler-builtins/libm/src/math/generic/fmaximum.rs index 898828b80c7ff..55a031e18ee8d 100644 --- a/compiler-builtins/libm/src/math/generic/fmaximum.rs +++ b/compiler-builtins/libm/src/math/generic/fmaximum.rs @@ -4,8 +4,8 @@ //! Per the spec, returns the canonicalized result of: //! - `x` if `x > y` //! - `y` if `y > x` +//! - +0.0 if x and y are zero with opposite signs //! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 //! //! Excluded from our implementation is sNaN handling. @@ -23,6 +23,5 @@ pub fn fmaximum<F: Float>(x: F, y: F) -> F { y }; - // Canonicalize - res * F::ONE + res.canonicalize() } diff --git a/compiler-builtins/libm/src/math/generic/fmaximum_num.rs b/compiler-builtins/libm/src/math/generic/fmaximum_num.rs index 05df6cbd4643e..2dc60b2d237f5 100644 --- a/compiler-builtins/libm/src/math/generic/fmaximum_num.rs +++ b/compiler-builtins/libm/src/math/generic/fmaximum_num.rs @@ -4,10 +4,10 @@ //! Per the spec, returns: //! - `x` if `x > y` //! - `y` if `y > x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 +//! - +0.0 if x and y are zero with opposite signs //! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN +//! - Non-NaN if one operand is NaN +//! - qNaN if both operands are NaNx //! //! Excluded from our implementation is sNaN handling. @@ -15,12 +15,15 @@ use crate::support::Float; #[inline] pub fn fmaximum_num<F: Float>(x: F, y: F) -> F { - let res = if x.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { + let res = if x > y || y.is_nan() { + x + } else if y > x || x.is_nan() { y - } else { + } else if x.is_sign_positive() { x + } else { + y }; - // Canonicalize - res * F::ONE + res.canonicalize() } diff --git a/compiler-builtins/libm/src/math/generic/fmin.rs b/compiler-builtins/libm/src/math/generic/fmin.rs index 0f86364d230b1..e2245bf9e137b 100644 --- a/compiler-builtins/libm/src/math/generic/fmin.rs +++ b/compiler-builtins/libm/src/math/generic/fmin.rs @@ -19,6 +19,5 @@ use crate::support::Float; #[inline] pub fn fmin<F: Float>(x: F, y: F) -> F { let res = if y.is_nan() || x < y { x } else { y }; - // Canonicalize - res * F::ONE + res.canonicalize() } diff --git a/compiler-builtins/libm/src/math/generic/fminimum.rs b/compiler-builtins/libm/src/math/generic/fminimum.rs index 8592ac5460ef0..aa68b1291d42b 100644 --- a/compiler-builtins/libm/src/math/generic/fminimum.rs +++ b/compiler-builtins/libm/src/math/generic/fminimum.rs @@ -4,8 +4,8 @@ //! Per the spec, returns the canonicalized result of: //! - `x` if `x < y` //! - `y` if `y < x` +//! - -0.0 if x and y are zero with opposite signs //! - qNaN if either operation is NaN -//! - Logic following +0.0 > -0.0 //! //! Excluded from our implementation is sNaN handling. @@ -23,6 +23,5 @@ pub fn fminimum<F: Float>(x: F, y: F) -> F { y }; - // Canonicalize - res * F::ONE + res.canonicalize() } diff --git a/compiler-builtins/libm/src/math/generic/fminimum_num.rs b/compiler-builtins/libm/src/math/generic/fminimum_num.rs index 6777bbf87721b..265bd4605ce39 100644 --- a/compiler-builtins/libm/src/math/generic/fminimum_num.rs +++ b/compiler-builtins/libm/src/math/generic/fminimum_num.rs @@ -4,10 +4,10 @@ //! Per the spec, returns: //! - `x` if `x < y` //! - `y` if `y < x` -//! - Non-NaN if one operand is NaN -//! - Logic following +0.0 > -0.0 +//! - -0.0 if x and y are zero with opposite signs //! - Either `x` or `y` if `x == y` and the signs are the same -//! - qNaN if either operand is a NaN +//! - Non-NaN if one operand is NaN +//! - qNaN if both operands are NaNx //! //! Excluded from our implementation is sNaN handling. @@ -15,12 +15,15 @@ use crate::support::Float; #[inline] pub fn fminimum_num<F: Float>(x: F, y: F) -> F { - let res = if y.is_nan() || x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) { + let res = if x > y || x.is_nan() { + y + } else if y > x || y.is_nan() { x - } else { + } else if x.is_sign_positive() { y + } else { + x }; - // Canonicalize - res * F::ONE + res.canonicalize() } diff --git a/compiler-builtins/libm/src/math/support/float_traits.rs b/compiler-builtins/libm/src/math/support/float_traits.rs index dd9f46209c11d..c3e7eeec245c8 100644 --- a/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/compiler-builtins/libm/src/math/support/float_traits.rs @@ -190,6 +190,15 @@ pub trait Float: Self::ONE.copysign(self) } } + + /// Make a best-effort attempt to canonicalize the number. Note that this is allowed + /// to be a nop and does not always quiet sNaNs. + fn canonicalize(self) -> Self { + // FIXME: LLVM often removes this. We should determine whether we can remove the operation, + // or switch to something based on `llvm.canonicalize` (which has crashes, + // <https://github.com/llvm/llvm-project/issues/32650>). + self * Self::ONE + } } /// Access the associated `Int` type from a float (helper to avoid ambiguous associated types). diff --git a/compiler-builtins/libm/src/math/support/macros.rs b/compiler-builtins/libm/src/math/support/macros.rs index 2b8fd580a50e5..550d2e92eb7c5 100644 --- a/compiler-builtins/libm/src/math/support/macros.rs +++ b/compiler-builtins/libm/src/math/support/macros.rs @@ -143,10 +143,12 @@ macro_rules! assert_biteq { let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits()); assert!( $crate::support::Float::biteq(l, r), - "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + "{}\nl: {l:?} ({lb:#0width$x} {lh})\nr: {r:?} ({rb:#0width$x} {rh})", format_args!($($tt)*), lb = l.to_bits(), + lh = $crate::support::Hexf(l), rb = r.to_bits(), + rh = $crate::support::Hexf(r), width = ((bits / 4) + 2) as usize, ); From 25c15fcadddc6e0f9ccee93fda441ad22ddf4eae Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Fri, 13 Jun 2025 15:42:06 +0000 Subject: [PATCH 32/42] Clean up and sort manifest keys Use a consistent ordering for top-level manifest keys, and remove those that are now redundant (`homapage` isn't supposed to be the same as `repository`, and `documentation` automatically points to docs.rs now). --- compiler-builtins/compiler-builtins/Cargo.toml | 9 +++------ compiler-builtins/libm/Cargo.toml | 10 ++++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler-builtins/compiler-builtins/Cargo.toml b/compiler-builtins/compiler-builtins/Cargo.toml index eabb3d6259943..22e240099a5f1 100644 --- a/compiler-builtins/compiler-builtins/Cargo.toml +++ b/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,14 +1,11 @@ [package] -authors = ["Jorge Aparicio <japaricious@gmail.com>"] name = "compiler_builtins" version = "0.1.160" -license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" -readme = "README.md" +authors = ["Jorge Aparicio <japaricious@gmail.com>"] +description = "Compiler intrinsics used by the Rust compiler." repository = "https://github.com/rust-lang/compiler-builtins" -homepage = "https://github.com/rust-lang/compiler-builtins" -documentation = "https://docs.rs/compiler_builtins" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" edition = "2024" -description = "Compiler intrinsics used by the Rust compiler." links = "compiler-rt" [lib] diff --git a/compiler-builtins/libm/Cargo.toml b/compiler-builtins/libm/Cargo.toml index b6fb5efcf76e5..63b4d3c277989 100644 --- a/compiler-builtins/libm/Cargo.toml +++ b/compiler-builtins/libm/Cargo.toml @@ -1,14 +1,12 @@ [package] +name = "libm" +version = "0.2.15" authors = ["Jorge Aparicio <jorge@japaric.io>"] -categories = ["no-std"] description = "libm in pure Rust" -documentation = "https://docs.rs/libm" +categories = ["no-std"] keywords = ["libm", "math"] -license = "MIT" -name = "libm" -readme = "README.md" repository = "https://github.com/rust-lang/compiler-builtins" -version = "0.2.15" +license = "MIT" edition = "2021" rust-version = "1.63" From c8e789e2f0e38e5a1174400cc1d29c871e45ab06 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Fri, 13 Jun 2025 15:44:45 +0000 Subject: [PATCH 33/42] Mark compiler-builtins as `publish = false` Now that this repository is a subtree, we have no need to continue publishing `compiler-builtins`. --- compiler-builtins/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler-builtins/compiler-builtins/Cargo.toml b/compiler-builtins/compiler-builtins/Cargo.toml index 22e240099a5f1..dffdcaf9430fc 100644 --- a/compiler-builtins/compiler-builtins/Cargo.toml +++ b/compiler-builtins/compiler-builtins/Cargo.toml @@ -6,6 +6,7 @@ description = "Compiler intrinsics used by the Rust compiler." repository = "https://github.com/rust-lang/compiler-builtins" license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" edition = "2024" +publish = false links = "compiler-rt" [lib] From 3aeeea5136880abc222341494f6f468b75891d48 Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Fri, 13 Jun 2025 20:04:49 -0700 Subject: [PATCH 34/42] Remove unneeded lifetimes from signature of BTreeSet::extract_if --- alloc/src/collections/btree/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alloc/src/collections/btree/set.rs b/alloc/src/collections/btree/set.rs index 51418036f428e..aa9e5fce1d4cc 100644 --- a/alloc/src/collections/btree/set.rs +++ b/alloc/src/collections/btree/set.rs @@ -1220,11 +1220,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` #[unstable(feature = "btree_extract_if", issue = "70530")] - pub fn extract_if<'a, F, R>(&'a mut self, range: R, pred: F) -> ExtractIf<'a, T, R, F, A> + pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, R: RangeBounds<T>, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { let (inner, alloc) = self.map.extract_if_inner(range); ExtractIf { pred, inner, alloc } @@ -1585,11 +1585,11 @@ where } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<'a, T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> +impl<T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, R: RangeBounds<T>, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { type Item = T; From 3a28dcf0dcaa4407e8b1636495112c509e5b0f1b Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Sat, 14 Jun 2025 03:38:53 +0000 Subject: [PATCH 35/42] Delete `.release-plz.toml` The config file is not needed anymore since compiler-builtins is no longer published. Removing it will resolve a CI failure. --- compiler-builtins/.release-plz.toml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 compiler-builtins/.release-plz.toml diff --git a/compiler-builtins/.release-plz.toml b/compiler-builtins/.release-plz.toml deleted file mode 100644 index 8023ade9bfd2f..0000000000000 --- a/compiler-builtins/.release-plz.toml +++ /dev/null @@ -1,13 +0,0 @@ -[workspace] -# As part of the release process, we delete `libm/Cargo.toml`. Since -# this is only run in CI, we shouldn't need to worry about it. -allow_dirty = true -publish_allow_dirty = true - -[[package]] -name = "compiler_builtins" -semver_check = false -changelog_include = ["libm"] # libm is included as part of builtins - -[[package]] -name = "libm" From 2beeeab21d25041e8b6108d3db58f379cd6b7fe1 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Sat, 14 Jun 2025 04:25:55 +0000 Subject: [PATCH 36/42] Update the upstream Rust version To prepare for merging from rust-lang/rust, set the version file to: d087f112b7 Auto merge of #134841 - estebank:serde-attr-4, r=wesleywiser --- compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-builtins/rust-version b/compiler-builtins/rust-version index e05aaa0573cab..73183983599ff 100644 --- a/compiler-builtins/rust-version +++ b/compiler-builtins/rust-version @@ -1 +1 @@ -df8102fe5f24f28a918660b0cd918d7331c3896e +d087f112b7d1323446c7b39a8b616aee7fa56b3d From 7f084e80656efb733120bb87701a73435946285a Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Sat, 14 Jun 2025 06:23:24 +0000 Subject: [PATCH 37/42] Work around out-of-tree testing with a shim crate Out-of-tree testing is broken with the most recent update from rust-lang/rust because it makes `compiler-builtins` depend on `core` by path, which isn't usually available. In order to enable testing outside of rust-lang/rust, add a new crate `builtins-shim` that uses the same source as `compiler-builtins` but drops the `core` dependency. This has replaced `compiler-builtins` as the workspace member and entrypoint for tests. --- compiler-builtins/Cargo.toml | 8 ++- compiler-builtins/builtins-shim/Cargo.toml | 63 +++++++++++++++++++ .../builtins-test-intrinsics/Cargo.toml | 2 +- compiler-builtins/builtins-test/Cargo.toml | 2 +- .../compiler-builtins/Cargo.toml | 6 ++ 5 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 compiler-builtins/builtins-shim/Cargo.toml diff --git a/compiler-builtins/Cargo.toml b/compiler-builtins/Cargo.toml index fb638f2fb379f..41350c6cb9909 100644 --- a/compiler-builtins/Cargo.toml +++ b/compiler-builtins/Cargo.toml @@ -1,8 +1,8 @@ [workspace] resolver = "2" members = [ + "builtins-shim", "builtins-test", - "compiler-builtins", "crates/josh-sync", "crates/libm-macros", "crates/musl-math-sys", @@ -14,8 +14,8 @@ members = [ ] default-members = [ + "builtins-shim", "builtins-test", - "compiler-builtins", "crates/libm-macros", "libm", "libm-test", @@ -26,6 +26,10 @@ exclude = [ # and `mangled-names` disabled, which is the opposite of what is needed for # other tests, so it makes sense to keep it out of the workspace. "builtins-test-intrinsics", + # We test via the `builtins-shim` crate, so exclude the `compiler-builtins` + # that has a dependency on `core`. See `builtins-shim/Cargo.toml` for more + # details. + "compiler-builtins", ] [profile.release] diff --git a/compiler-builtins/builtins-shim/Cargo.toml b/compiler-builtins/builtins-shim/Cargo.toml new file mode 100644 index 0000000000000..8eb880c6fd1d0 --- /dev/null +++ b/compiler-builtins/builtins-shim/Cargo.toml @@ -0,0 +1,63 @@ +# NOTE: Must be kept in sync with `../compiler-builtins/Cargo.toml`. +# +# The manifest at `../compiler-builtins` is what actually gets used in the +# rust-lang/rust tree; however, we can't build it out of tree because it +# depends on `core` by path, and even optional Cargo dependencies need to be +# available at build time. So, we work around this by having this "shim" +# manifest that is identical except for the `core` dependency and forwards +# to the same sources, which acts as the `compiler-builtins` Cargo entrypoint +# for out of tree testing + +[package] +name = "compiler_builtins" +version = "0.1.160" +authors = ["Jorge Aparicio <japaricious@gmail.com>"] +description = "Compiler intrinsics used by the Rust compiler." +repository = "https://github.com/rust-lang/compiler-builtins" +license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" +edition = "2024" +publish = false +links = "compiler-rt" + +build = "../compiler-builtins/build.rs" + +[lib] +path = "../compiler-builtins/src/lib.rs" +bench = false +doctest = false +test = false + +[build-dependencies] +cc = { optional = true, version = "1.2" } + +[features] +default = ["compiler-builtins"] + +# Enable compilation of C code in compiler-rt, filling in some more optimized +# implementations and also filling in unimplemented intrinsics +c = ["dep:cc"] + +# Workaround for the Cranelift codegen backend. Disables any implementations +# which use inline assembly and fall back to pure Rust versions (if available). +no-asm = [] + +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + +# Flag this library as the unstable compiler-builtins lib +compiler-builtins = [] + +# Generate memory-related intrinsics like memcpy +mem = [] + +# Mangle all names so this can be linked in with other versions or other +# compiler-rt implementations. Also used for testing +mangled-names = [] + +# Only used in the compiler's build system +rustc-dep-of-std = ["compiler-builtins"] + +# This makes certain traits and function specializations public that +# are not normally public but are required by the `builtins-test` +unstable-public-internals = [] diff --git a/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 064b7cad2f64b..e73a1f7b17e5b 100644 --- a/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [dependencies] -compiler_builtins = { path = "../compiler-builtins", features = ["compiler-builtins"] } +compiler_builtins = { path = "../builtins-shim", features = ["compiler-builtins"] } panic-handler = { path = "../crates/panic-handler" } [features] diff --git a/compiler-builtins/builtins-test/Cargo.toml b/compiler-builtins/builtins-test/Cargo.toml index c7742aa24275f..093d4633f8746 100644 --- a/compiler-builtins/builtins-test/Cargo.toml +++ b/compiler-builtins/builtins-test/Cargo.toml @@ -17,7 +17,7 @@ rustc_apfloat = "0.2.2" iai-callgrind = { version = "0.14.1", optional = true } [dependencies.compiler_builtins] -path = "../compiler-builtins" +path = "../builtins-shim" default-features = false features = ["unstable-public-internals"] diff --git a/compiler-builtins/compiler-builtins/Cargo.toml b/compiler-builtins/compiler-builtins/Cargo.toml index 7276a68519912..c5446cd76e326 100644 --- a/compiler-builtins/compiler-builtins/Cargo.toml +++ b/compiler-builtins/compiler-builtins/Cargo.toml @@ -1,3 +1,9 @@ +# NOTE: Must be kept in sync with `../builtins-shim/Cargo.toml`. +# +# This manifest is actually used in-tree by rust-lang/rust, +# `../builtins-shim/Cargo.toml` is used by out-of-tree testing. See the other +# manifest for further details. + [package] name = "compiler_builtins" version = "0.1.160" From 7204ad4e500a6e509026a49fa4629db85357ab32 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 6 Dec 2024 09:06:51 +0000 Subject: [PATCH 38/42] Remove all support for wasm's legacy ABI --- proc_macro/src/bridge/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/proc_macro/src/bridge/mod.rs b/proc_macro/src/bridge/mod.rs index 75d82d7465404..d60a76fff5dc5 100644 --- a/proc_macro/src/bridge/mod.rs +++ b/proc_macro/src/bridge/mod.rs @@ -7,9 +7,6 @@ //! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). #![deny(unsafe_code)] -// proc_macros anyway don't work on wasm hosts so while both sides of this bridge can -// be built with different versions of rustc, the wasm ABI changes don't really matter. -#![allow(wasm_c_abi)] use std::hash::Hash; use std::ops::{Bound, Range}; From 4136fda68f141f5af451dac6858104944a6ed883 Mon Sep 17 00:00:00 2001 From: Christopher Berner <me@cberner.com> Date: Wed, 28 May 2025 21:01:04 -0700 Subject: [PATCH 39/42] Stabilize "file_lock" feature --- std/src/fs.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/std/src/fs.rs b/std/src/fs.rs index 0cd794fd3efbb..865ea620a283f 100644 --- a/std/src/fs.rs +++ b/std/src/fs.rs @@ -121,7 +121,7 @@ pub struct File { /// /// [`try_lock`]: File::try_lock /// [`try_lock_shared`]: File::try_lock_shared -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub enum TryLockError { /// The lock could not be acquired due to an I/O error on the file. The standard library will /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] @@ -366,10 +366,10 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result inner(path.as_ref(), contents.as_ref()) } -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl error::Error for TryLockError {} -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -379,7 +379,7 @@ impl fmt::Debug for TryLockError { } } -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl fmt::Display for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -390,7 +390,7 @@ impl fmt::Display for TryLockError { } } -#[unstable(feature = "file_lock", issue = "130994")] +#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] impl From<TryLockError> for io::Error { fn from(err: TryLockError) -> io::Error { match err { @@ -713,7 +713,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -722,7 +721,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn lock(&self) -> io::Result<()> { self.inner.lock() } @@ -766,7 +765,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -775,7 +773,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn lock_shared(&self) -> io::Result<()> { self.inner.lock_shared() } @@ -824,7 +822,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { @@ -840,7 +837,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn try_lock(&self) -> Result<(), TryLockError> { self.inner.try_lock() } @@ -888,7 +885,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { @@ -905,7 +901,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.inner.try_lock_shared() } @@ -933,7 +929,6 @@ impl File { /// # Examples /// /// ```no_run - /// #![feature(file_lock)] /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { @@ -943,7 +938,7 @@ impl File { /// Ok(()) /// } /// ``` - #[unstable(feature = "file_lock", issue = "130994")] + #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")] pub fn unlock(&self) -> io::Result<()> { self.inner.unlock() } From 2037fc5141d121d0e8872ca92b73c184219cc3ce Mon Sep 17 00:00:00 2001 From: Mara Bos <m-ou.se@m-ou.se> Date: Wed, 11 Jun 2025 18:28:17 +0200 Subject: [PATCH 40/42] Test Debug for Location. --- coretests/tests/panic/location.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/coretests/tests/panic/location.rs b/coretests/tests/panic/location.rs index d20241d838001..5ce0b06e90e1a 100644 --- a/coretests/tests/panic/location.rs +++ b/coretests/tests/panic/location.rs @@ -29,3 +29,11 @@ fn location_const_column() { const COLUMN: u32 = CALLER.column(); assert_eq!(COLUMN, 40); } + +#[test] +fn location_debug() { + let f = format!("{:?}", Location::caller()); + assert!(f.contains(&format!("{:?}", file!()))); + assert!(f.contains("35")); + assert!(f.contains("29")); +} From d91ee16e727439ca376718cef68c13a17e59ebb2 Mon Sep 17 00:00:00 2001 From: Trevor Gross <tmgross@umich.edu> Date: Mon, 16 Jun 2025 07:00:13 +0000 Subject: [PATCH 41/42] Update the `backtrace` submodule Pick up the following pull requests: * ci: remove binary size check (not relevant in rust-lang/rust) <https://github.com/rust-lang/backtrace-rs/pull/710> * Upgrade `ruzstd`, `object`, and `addr2line` to the latest versions <https://github.com/rust-lang/backtrace-rs/pull/718> --- backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtrace b/backtrace index 6c882eb11984d..b65ab935fb2e0 160000 --- a/backtrace +++ b/backtrace @@ -1 +1 @@ -Subproject commit 6c882eb11984d737f62e85f36703effaf34c2453 +Subproject commit b65ab935fb2e0d59dba8966ffca09c9cc5a5f57c From 1ac5cf095e1c907ee8b6723c48465eef835c1068 Mon Sep 17 00:00:00 2001 From: Yotam Ofek <yotam.ofek@gmail.com> Date: Mon, 9 Jun 2025 09:21:33 +0000 Subject: [PATCH 42/42] Add documentation for `PathBuf`'s `FromIterator` and `Extend` impls --- std/src/path.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/std/src/path.rs b/std/src/path.rs index 826d9f0f39dc6..0469db0814c1d 100644 --- a/std/src/path.rs +++ b/std/src/path.rs @@ -1882,6 +1882,19 @@ impl FromStr for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl<P: AsRef<Path>> FromIterator<P> for PathBuf { + /// Creates a new `PathBuf` from the [`Path`] elements of an iterator. + /// + /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path + /// [components](Components). + /// + /// # Examples + /// ``` + /// # use std::path::PathBuf; + /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]); + /// assert_eq!(path, PathBuf::from("/tmp/foo/bar")); + /// ``` + /// + /// See documentation for [`push`](Self::push) for more details on how the path is constructed. fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf { let mut buf = PathBuf::new(); buf.extend(iter); @@ -1891,6 +1904,20 @@ impl<P: AsRef<Path>> FromIterator<P> for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl<P: AsRef<Path>> Extend<P> for PathBuf { + /// Extends `self` with [`Path`] elements from `iter`. + /// + /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path + /// [components](Components). + /// + /// # Examples + /// ``` + /// # use std::path::PathBuf; + /// let mut path = PathBuf::from("/tmp"); + /// path.extend(["foo", "bar", "file.txt"]); + /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt")); + /// ``` + /// + /// See documentation for [`push`](Self::push) for more details on how the path is constructed. fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) { iter.into_iter().for_each(move |p| self.push(p.as_ref())); }