diff --git a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch index 340f6cc9b0e7c..2a6bfe8164579 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch @@ -4,13 +4,13 @@ Date: Sun, 15 Feb 2026 14:06:49 +0000 Subject: [PATCH] Disable f16 math tests for cranelift --- - coretests/tests/floats/mod.rs | 26 +++++++++++++------------- + coretests/tests/num/floats.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs index c61961f8584..d7b4fa20322 100644 ---- a/coretests/tests/floats/mod.rs -+++ b/coretests/tests/floats/mod.rs +--- a/coretests/tests/num/floats.rs ++++ b/coretests/tests/num/floats.rs @@ -1534,7 +1534,7 @@ fn s_nan() -> Float { name: powf, attrs: { @@ -128,6 +128,5 @@ index c61961f8584..d7b4fa20322 100644 f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, test { --- +-- 2.50.1 - diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 72112f8b01133..76229b5dae7f3 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -181,7 +181,6 @@ mod cmp; mod const_ptr; mod convert; mod ffi; -mod floats; mod fmt; mod future; mod hash; diff --git a/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs b/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs new file mode 100644 index 0000000000000..2a82ae326c223 --- /dev/null +++ b/library/coretests/tests/num/float_ieee754_flt2dec_dec2flt.rs @@ -0,0 +1,166 @@ +//! IEEE 754 floating point compliance tests +//! +//! To understand IEEE 754's requirements on a programming language, one must understand that the +//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any +//! one component. That means the hardware, language, and even libraries are considered part of +//! conforming floating point support in a programming environment. +//! +//! A programming language's duty, accordingly, is: +//! 1. offer access to the hardware where the hardware offers support +//! 2. provide operations that fulfill the remaining requirements of the standard +//! 3. provide the ability to write additional software that can fulfill those requirements +//! +//! This may be fulfilled in any combination that the language sees fit. However, to claim that +//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without +//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined +//! as complete support for at least one specified floating point type as an "arithmetic" and +//! "interchange" format, plus specified type conversions to "external character sequences" and +//! integer types. +//! +//! For our purposes, +//! "interchange format" => f16, f32, f64, f128 +//! "arithmetic format" => f16, f32, f64, f128, and any "soft floats" +//! "external character sequence" => str from any float +//! "integer format" => {i,u}{8,16,32,64,128} +//! +//! None of these tests are against Rust's own implementation. They are only tests against the +//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. +//! Please consider this carefully when adding, removing, or reorganizing these tests. They are +//! here so that it is clear what tests are required by the standard and what can be changed. + +use core::fmt; +use core::str::FromStr; + +use crate::num::{assert_biteq, float_test}; + +/// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts +/// of the formatting infrastructure, which makes it ideal for testing here. +#[track_caller] +fn string_roundtrip(x: T) -> T +where + T: FromStr + fmt::Display, +{ + x.to_string().parse::().unwrap() +} + +// FIXME(f128): Tests are disabled while we don't have parsing / printing + +// We must preserve signs on all numbers. That includes zero. +// -0 and 0 are == normally, so test bit equality. +float_test! { + name: preserve_signed_zero, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + let neg0 = flt(-0.0); + let pos0 = flt(0.0); + assert_biteq!(neg0, string_roundtrip(neg0)); + assert_biteq!(pos0, string_roundtrip(pos0)); + assert_ne!(neg0.to_bits(), pos0.to_bits()); + } +} + +float_test! { + name: preserve_signed_infinity, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + let neg_inf = Float::NEG_INFINITY; + let pos_inf = Float::INFINITY; + assert_biteq!(neg_inf, string_roundtrip(neg_inf)); + assert_biteq!(pos_inf, string_roundtrip(pos_inf)); + assert_ne!(neg_inf.to_bits(), pos_inf.to_bits()); + } +} + +float_test! { + name: infinity_to_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + assert!( + match Float::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }, + "Infinity must write to a string as some casing of inf or infinity, with an optional +." + ); + assert!( + match Float::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }, + "Negative Infinity must write to a string as some casing of -inf or -infinity" + ); + } +} + +float_test! { + name: nan_to_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + assert!( + match Float::NAN.to_string().to_lowercase().as_str() { + "nan" | "+nan" | "-nan" => true, + _ => false, + }, + "NaNs must write to a string as some casing of nan." + ) + } +} + +float_test! { + name: infinity_from_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + // "+"?("inf"|"infinity") in any case => Infinity + assert_biteq!(Float::INFINITY, Float::from_str("infinity").unwrap()); + assert_biteq!(Float::INFINITY, Float::from_str("inf").unwrap()); + assert_biteq!(Float::INFINITY, Float::from_str("+infinity").unwrap()); + assert_biteq!(Float::INFINITY, Float::from_str("+inf").unwrap()); + // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd + assert_biteq!(Float::INFINITY, Float::from_str("+iNfInItY").unwrap()); + + // "-inf"|"-infinity" in any case => Negative Infinity + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-infinity").unwrap()); + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-inf").unwrap()); + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INF").unwrap()); + assert_biteq!(Float::NEG_INFINITY, Float::from_str("-INFinity").unwrap()); + + } +} + +float_test! { + name: qnan_from_str, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(false)], + }, + test { + // ("+"|"-"")?"s"?"nan" in any case => qNaN + assert!("nan".parse::().unwrap().is_nan()); + assert!("-nan".parse::().unwrap().is_nan()); + assert!("+nan".parse::().unwrap().is_nan()); + assert!("+NAN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); + } +} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/num/floats.rs similarity index 99% rename from library/coretests/tests/floats/mod.rs rename to library/coretests/tests/num/floats.rs index c9bbff266d90f..d87f850944503 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/num/floats.rs @@ -2,7 +2,7 @@ use std::hint::black_box; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -trait TestableFloat: Sized { +pub(crate) trait TestableFloat: Sized { const BITS: u32; /// Unsigned int with the same size, for converting to/from bits. type Int; @@ -224,7 +224,7 @@ impl TestableFloat for f128 { } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { +pub(crate) const fn lim_for_ty(_x: T) -> T { T::APPROX } @@ -232,7 +232,9 @@ const fn lim_for_ty(_x: T) -> T { /// 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)) }}; + ($a:expr, $b:expr $(,)?) => {{ + assert_approx_eq!($a, $b, $crate::num::floats::lim_for_ty($a)) + }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -270,8 +272,8 @@ macro_rules! assert_biteq { // We rely on the `Float` type being brought in scope by the macros below. l: Float = l, r: Float = r, - lb: ::Int = l.to_bits(), - rb: ::Int = r.to_bits(), + lb: ::Int = l.to_bits(), + rb: ::Int = r.to_bits(), width: usize = ((bits / 4) + 2) as usize, ); }}; @@ -312,6 +314,7 @@ macro_rules! float_test { test $test:block ) => { mod $name { + #[allow(unused_imports)] use super::*; #[test] @@ -360,6 +363,7 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { + #[allow(unused_imports)] use super::*; #[test] @@ -410,6 +414,9 @@ macro_rules! float_test { }; } +pub(crate) use assert_biteq; +pub(crate) use float_test; + float_test! { name: num, attrs: { diff --git a/library/coretests/tests/num/ieee754.rs b/library/coretests/tests/num/ieee754.rs deleted file mode 100644 index b0f6a7545aa93..0000000000000 --- a/library/coretests/tests/num/ieee754.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! IEEE 754 floating point compliance tests -//! -//! To understand IEEE 754's requirements on a programming language, one must understand that the -//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any -//! one component. That means the hardware, language, and even libraries are considered part of -//! conforming floating point support in a programming environment. -//! -//! A programming language's duty, accordingly, is: -//! 1. offer access to the hardware where the hardware offers support -//! 2. provide operations that fulfill the remaining requirements of the standard -//! 3. provide the ability to write additional software that can fulfill those requirements -//! -//! This may be fulfilled in any combination that the language sees fit. However, to claim that -//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without -//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined -//! as complete support for at least one specified floating point type as an "arithmetic" and -//! "interchange" format, plus specified type conversions to "external character sequences" and -//! integer types. -//! -//! For our purposes, -//! "interchange format" => f32, f64 -//! "arithmetic format" => f32, f64, and any "soft floats" -//! "external character sequence" => str from any float -//! "integer format" => {i,u}{8,16,32,64,128} -//! -//! None of these tests are against Rust's own implementation. They are only tests against the -//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. -//! Please consider this carefully when adding, removing, or reorganizing these tests. They are -//! here so that it is clear what tests are required by the standard and what can be changed. - -use ::core::str::FromStr; - -// IEEE 754 for many tests is applied to specific bit patterns. -// These generally are not applicable to NaN, however. -macro_rules! assert_biteq { - ($lhs:expr, $rhs:expr) => { - assert_eq!($lhs.to_bits(), $rhs.to_bits()) - }; -} - -// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts -// of the formatting infrastructure, which makes it ideal for testing here. -macro_rules! roundtrip { - ($f:expr => $t:ty) => { - ($f).to_string().parse::<$t>().unwrap() - }; -} - -macro_rules! assert_floats_roundtrip { - ($f:ident) => { - assert_biteq!(f32::$f, roundtrip!(f32::$f => f32)); - assert_biteq!(f64::$f, roundtrip!(f64::$f => f64)); - }; - ($f:expr) => { - assert_biteq!($f as f32, roundtrip!($f => f32)); - assert_biteq!($f as f64, roundtrip!($f => f64)); - } -} - -macro_rules! assert_floats_bitne { - ($lhs:ident, $rhs:ident) => { - assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits()); - assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits()); - }; - ($lhs:expr, $rhs:expr) => { - assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs)); - assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs)); - }; -} - -// We must preserve signs on all numbers. That includes zero. -// -0 and 0 are == normally, so test bit equality. -#[test] -fn preserve_signed_zero() { - assert_floats_roundtrip!(-0.0); - assert_floats_roundtrip!(0.0); - assert_floats_bitne!(0.0, -0.0); -} - -#[test] -fn preserve_signed_infinity() { - assert_floats_roundtrip!(INFINITY); - assert_floats_roundtrip!(NEG_INFINITY); - assert_floats_bitne!(INFINITY, NEG_INFINITY); -} - -#[test] -fn infinity_to_str() { - assert!(match f32::INFINITY.to_string().to_lowercase().as_str() { - "+infinity" | "infinity" => true, - "+inf" | "inf" => true, - _ => false, - }); - assert!( - match f64::INFINITY.to_string().to_lowercase().as_str() { - "+infinity" | "infinity" => true, - "+inf" | "inf" => true, - _ => false, - }, - "Infinity must write to a string as some casing of inf or infinity, with an optional +." - ); -} - -#[test] -fn neg_infinity_to_str() { - assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() { - "-infinity" | "-inf" => true, - _ => false, - }); - assert!( - match f64::NEG_INFINITY.to_string().to_lowercase().as_str() { - "-infinity" | "-inf" => true, - _ => false, - }, - "Negative Infinity must write to a string as some casing of -inf or -infinity" - ) -} - -#[test] -fn nan_to_str() { - assert!( - match f32::NAN.to_string().to_lowercase().as_str() { - "nan" | "+nan" | "-nan" => true, - _ => false, - }, - "NaNs must write to a string as some casing of nan." - ) -} - -// "+"?("inf"|"infinity") in any case => Infinity -#[test] -fn infinity_from_str() { - assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap()); - // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd - assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap()); -} - -// "-inf"|"-infinity" in any case => Negative Infinity -#[test] -fn neg_infinity_from_str() { - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap()); -} - -// ("+"|"-"")?"s"?"nan" in any case => qNaN -#[test] -fn qnan_from_str() { - assert!("nan".parse::().unwrap().is_nan()); - assert!("-nan".parse::().unwrap().is_nan()); - assert!("+nan".parse::().unwrap().is_nan()); - assert!("+NAN".parse::().unwrap().is_nan()); - assert!("-NaN".parse::().unwrap().is_nan()); -} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index 73b0e2333feee..e0214c6ae6868 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -25,9 +25,10 @@ mod bignum; mod carryless_mul; mod const_from; mod dec2flt; +mod float_ieee754_flt2dec_dec2flt; mod float_iter_sum_identity; +mod floats; mod flt2dec; -mod ieee754; mod int_log; mod int_sqrt; mod midpoint; @@ -36,6 +37,8 @@ mod niche_types; mod ops; mod wrapping; +use floats::{assert_biteq, float_test}; + /// Adds the attribute to all items in the block. macro_rules! cfg_block { ($(#[$attr:meta]{$($it:item)*})*) => {$($(