From fdb660e8514ad09ebd9a478516d66b924c839f55 Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sun, 25 May 2025 20:16:44 +0100 Subject: [PATCH 1/9] Limit the size of cgu names when using the `-Zhuman-readable-cgu-names` option Prior to this change, cgu names could be generated which would result in filenames longer than the limit imposed by the OS. --- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 26 ++++++++++++++++++- .../rustc_monomorphize/src/partitioning.rs | 10 +++---- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index cb3fdd4d3f76e..7135b8f04a2e3 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -51,6 +51,7 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(ptr_alignment_type)] +#![feature(round_char_boundary)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(trusted_len)] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 7243f87ee6380..47ba850d50dd4 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::fmt; use std::hash::Hash; @@ -468,6 +469,29 @@ impl<'tcx> CodegenUnit<'tcx> { hash.as_u128().to_base_fixed_len(CASE_INSENSITIVE) } + pub fn shorten_name(human_readable_name: &str) -> Cow<'_, str> { + // Set a limit a somewhat below the common platform limits for file names. + const MAX_CGU_NAME_LENGTH: usize = 200; + const TRUNCATED_NAME_PREFIX: &str = "-trunc-"; + if human_readable_name.len() > MAX_CGU_NAME_LENGTH { + let mangled_name = Self::mangle_name(human_readable_name); + // Determine a safe byte offset to truncate the name to + let truncate_to = human_readable_name.floor_char_boundary( + MAX_CGU_NAME_LENGTH - TRUNCATED_NAME_PREFIX.len() - mangled_name.len(), + ); + format!( + "{}{}{}", + &human_readable_name[..truncate_to], + TRUNCATED_NAME_PREFIX, + mangled_name + ) + .into() + } else { + // If the name is short enough, we can just return it as is. + human_readable_name.into() + } + } + pub fn compute_size_estimate(&mut self) { // The size of a codegen unit as the sum of the sizes of the items // within it. @@ -604,7 +628,7 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> { let cgu_name = self.build_cgu_name_no_mangle(cnum, components, special_suffix); if self.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu_name + Symbol::intern(&CodegenUnit::shorten_name(cgu_name.as_str())) } else { Symbol::intern(&CodegenUnit::mangle_name(cgu_name.as_str())) } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index b4169a060d4d6..49025673bbd2f 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -461,15 +461,15 @@ fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(new_cgu_name)); + let new_cgu_name = if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + Symbol::intern(&CodegenUnit::shorten_name(new_cgu_name)) } else { // If we don't require CGU names to be human-readable, // we use a fixed length hash of the composite CGU name // instead. - let new_cgu_name = CodegenUnit::mangle_name(new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } + Symbol::intern(&CodegenUnit::mangle_name(new_cgu_name)) + }; + cgu.set_name(new_cgu_name); } } From 7742d0e230b602a0a73d38b32de47449f3306450 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Jun 2025 15:56:33 +0200 Subject: [PATCH 2/9] coretests: move float tests from num to floats module and use a more flexible macro to generate them --- library/coretests/tests/floats/mod.rs | 548 ++++++++++++++++++++++++++ library/coretests/tests/num/mod.rs | 353 ----------------- 2 files changed, 548 insertions(+), 353 deletions(-) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 7e27028a2a2d1..f9b6c85f87105 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -52,6 +52,119 @@ macro_rules! 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; +} + +/// Generate float tests for all our float types, for compile-time and run-time behavior. +/// +/// By default all tests run for all float types. Configuration can be applied via `attrs`. +/// +/// ```ignore (this is only a sketch) +/// float_test! { +/// name: fn_name, /* function under test */ +/// attrs: { +/// // Apply a configuration to the test for a single type +/// f16: #[cfg(target_has_reliable_f16_math)], +/// // Types can be excluded with `cfg(false)` +/// f64: #[cfg(false)], +/// }, +/// test { +/// /* write tests here, using `Float` as the type */ +/// } +/// } +macro_rules! float_test { + ( + name: $name:ident, + attrs: { + $(const: #[ $($const_meta:meta),+ ] ,)? + $(f16: #[ $($f16_meta:meta),+ ] ,)? + $(const f16: #[ $($f16_const_meta:meta),+ ] ,)? + $(f32: #[ $($f32_meta:meta),+ ] ,)? + $(const f32: #[ $($f32_const_meta:meta),+ ] ,)? + $(f64: #[ $($f64_meta:meta),+ ] ,)? + $(const f64: #[ $($f64_const_meta:meta),+ ] ,)? + $(f128: #[ $($f128_meta:meta),+ ] ,)? + $(const f128: #[ $($f128_const_meta:meta),+ ] ,)? + }, + test<$fty:ident> $test:block + ) => { + mod $name { + #[test] + $( $( #[$f16_meta] )+ )? + fn test_f16() { + type $fty = f16; + $test + } + + #[test] + $( $( #[$f32_meta] )+ )? + fn test_f32() { + type $fty = f32; + $test + } + + #[test] + $( $( #[$f64_meta] )+ )? + fn test_f64() { + type $fty = f64; + $test + } + + #[test] + $( $( #[$f128_meta] )+ )? + fn test_f128() { + type $fty = f128; + $test + } + + $( $( #[$const_meta] )+ )? + mod const_ { + use $crate::floats::const_asserts::assert_eq; + + #[test] + $( $( #[$f16_const_meta] )+ )? + fn test_f16() { + type $fty = f16; + const { $test } + } + + #[test] + $( $( #[$f32_const_meta] )+ )? + fn test_f32() { + type $fty = f32; + const { $test } + } + + #[test] + $( $( #[$f64_const_meta] )+ )? + fn test_f64() { + type $fty = f64; + const { $test } + } + + #[test] + $( $( #[$f128_const_meta] )+ )? + fn test_f128() { + type $fty = f128; + const { $test } + } + } + } + }; +} + /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where @@ -75,3 +188,438 @@ mod f128; mod f16; mod f32; mod f64; + +float_test! { + name: min, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::NAN.min(Float::NAN).is_nan()); + } +} + +float_test! { + name: max, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::NAN.max(Float::NAN).is_nan()); + } +} + +float_test! { + name: minimum, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(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()); + assert!((-9.0 as Float).minimum(Float::NAN).is_nan()); + assert!(Float::NAN.minimum(Float::NAN).is_nan()); + } +} + +float_test! { + name: maximum, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(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()); + assert!((-9.0 as Float).maximum(Float::NAN).is_nan()); + assert!(Float::NAN.maximum(Float::NAN).is_nan()); + } +} + +float_test! { + name: midpoint, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!( + (Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE), + Float::MIN_POSITIVE + ); + assert_eq!( + (-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!( + Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), + Float::NEG_INFINITY + ); + 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()); + } +} + +// Separate test since the `for` loops cannot be run in `const`. +float_test! { + name: midpoint_large_magnitude, + attrs: { + const: #[cfg(false)], + // FIXME(f16_f128): `powi` does not work in Miri for these types + f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], + f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + }, + test { + // test if large differences in magnitude are still correctly computed. + // NOTE: that because of how small x and y are, x + y can never overflow + // so (x + y) / 2.0 is always correct + // in particular, `2.pow(i)` will never be at the max exponent, so it could + // be safely doubled, while j is significantly smaller. + for i in Float::MAX_EXP.saturating_sub(64)..Float::MAX_EXP { + for j in 0..64u8 { + let large = (2.0 as Float).powi(i); + // a much smaller number, such that there is no chance of overflow to test + // potential double rounding in midpoint's implementation. + let small = (2.0 as Float).powi(Float::MAX_EXP - 1) + * Float::EPSILON + * Float::from(j); + + let naive = (large + small) / 2.0; + let midpoint = large.midpoint(small); + + assert_eq!(naive, midpoint); + } + } + } +} + +float_test! { + name: abs, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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); + } +} + +float_test! { + name: copysign, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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); + } +} + +float_test! { + name: rem_euclid, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!((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()); + assert!(Float::NAN.rem_euclid(Float::INFINITY).is_nan()); + } +} + +float_test! { + name: div_euclid, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((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()); + assert!(Float::NAN.div_euclid(Float::INFINITY).is_nan()); + } +} + +float_test! { + name: floor, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::NAN.floor().is_nan()); + assert_eq!(Float::INFINITY.floor(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); + } +} + +float_test! { + name: ceil, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::NAN.ceil().is_nan()); + assert_eq!(Float::INFINITY.ceil(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); + } +} + +float_test! { + name: round, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::NAN.round().is_nan()); + assert_eq!(Float::INFINITY.round(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); + } +} + +float_test! { + name: round_ties_even, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(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); + } +} + +float_test! { + name: trunc, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::NAN.trunc().is_nan()); + assert_eq!(Float::INFINITY.trunc(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); + } +} + +float_test! { + name: fract, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + 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!(Float::MIN_POSITIVE.fract().is_sign_positive()); + assert_eq!((-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()); + assert!(Float::NEG_INFINITY.fract().is_nan()); + } +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index c68b569f86b3a..6611aa57866ff 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -730,356 +730,3 @@ assume_usize_width! { } } } - -// FIXME(141726): there is a lot of duplication between the following tests and -// the tests in `coretests/tests/floats/f*.rs` -// See issue https://github.com/rust-lang/rust/issues/141726 for more details. -macro_rules! test_float { - ($modname: ident, $fassert: ident, $fty: ty) => { - mod $modname { - #[test] - fn min() { - $fassert!((0.0 as $fty).min(0.0), 0.0); - $fassert!((0.0 as $fty).min(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).min(-0.0), -0.0); - $fassert!((-0.0 as $fty).min(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).min(9.0), 9.0); - $fassert!((-9.0 as $fty).min(0.0), -9.0); - $fassert!((0.0 as $fty).min(9.0), 0.0); - $fassert!((0.0 as $fty).min(9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).min(9.0), -0.0); - $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); - $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!(<$fty>::INFINITY.min(9.0), 9.0); - $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); - $fassert!(<$fty>::INFINITY.min(-9.0), -9.0); - $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); - $fassert!(<$fty>::NEG_INFINITY.min(9.0), <$fty>::NEG_INFINITY); - $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.min(-9.0), <$fty>::NEG_INFINITY); - $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NAN.min(9.0), 9.0); - $fassert!(<$fty>::NAN.min(-9.0), -9.0); - $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); - $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); - $fassert!(<$fty>::NAN.min(<$fty>::NAN).is_nan()); - } - #[test] - fn max() { - $fassert!((0.0 as $fty).max(0.0), 0.0); - $fassert!((0.0 as $fty).max(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).max(-0.0), -0.0); - $fassert!((-0.0 as $fty).max(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).max(9.0), 9.0); - $fassert!((-9.0 as $fty).max(0.0), 0.0); - $fassert!((-9.0 as $fty).max(0.0).is_sign_positive()); - $fassert!((-9.0 as $fty).max(-0.0), -0.0); - $fassert!((-9.0 as $fty).max(-0.0).is_sign_negative()); - $fassert!((0.0 as $fty).max(9.0), 9.0); - $fassert!((0.0 as $fty).max(-9.0), 0.0); - $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).max(-9.0), -0.0); - $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!(<$fty>::INFINITY.max(9.0), <$fty>::INFINITY); - $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.max(-9.0), <$fty>::INFINITY); - $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.max(9.0), 9.0); - $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); - $fassert!(<$fty>::NEG_INFINITY.max(-9.0), -9.0); - $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); - $fassert!(<$fty>::NAN.max(9.0), 9.0); - $fassert!(<$fty>::NAN.max(-9.0), -9.0); - $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); - $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); - $fassert!(<$fty>::NAN.max(<$fty>::NAN).is_nan()); - } - #[test] - fn minimum() { - $fassert!((0.0 as $fty).minimum(0.0), 0.0); - $fassert!((0.0 as $fty).minimum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).minimum(0.0), -0.0); - $fassert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); - $fassert!((-0.0 as $fty).minimum(-0.0), -0.0); - $fassert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).minimum(9.0), 9.0); - $fassert!((-9.0 as $fty).minimum(0.0), -9.0); - $fassert!((0.0 as $fty).minimum(9.0), 0.0); - $fassert!((0.0 as $fty).minimum(9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).minimum(9.0), -0.0); - $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); - $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!(<$fty>::INFINITY.minimum(9.0), 9.0); - $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); - $fassert!(<$fty>::INFINITY.minimum(-9.0), -9.0); - $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); - $fassert!(<$fty>::NEG_INFINITY.minimum(9.0), <$fty>::NEG_INFINITY); - $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.minimum(-9.0), <$fty>::NEG_INFINITY); - $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NAN.minimum(9.0).is_nan()); - $fassert!(<$fty>::NAN.minimum(-9.0).is_nan()); - $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.minimum(<$fty>::NAN).is_nan()); - } - #[test] - fn maximum() { - $fassert!((0.0 as $fty).maximum(0.0), 0.0); - $fassert!((0.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(0.0), 0.0); - $fassert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(-0.0), -0.0); - $fassert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).maximum(9.0), 9.0); - $fassert!((-9.0 as $fty).maximum(0.0), 0.0); - $fassert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-9.0 as $fty).maximum(-0.0), -0.0); - $fassert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); - $fassert!((0.0 as $fty).maximum(9.0), 9.0); - $fassert!((0.0 as $fty).maximum(-9.0), 0.0); - $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); - $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!(<$fty>::INFINITY.maximum(9.0), <$fty>::INFINITY); - $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.maximum(-9.0), <$fty>::INFINITY); - $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.maximum(9.0), 9.0); - $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); - $fassert!(<$fty>::NEG_INFINITY.maximum(-9.0), -9.0); - $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); - $fassert!(<$fty>::NAN.maximum(9.0).is_nan()); - $fassert!(<$fty>::NAN.maximum(-9.0).is_nan()); - $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.maximum(<$fty>::NAN).is_nan()); - } - #[test] - fn midpoint() { - $fassert!((0.5 as $fty).midpoint(0.5), 0.5); - $fassert!((0.5 as $fty).midpoint(2.5), 1.5); - $fassert!((3.0 as $fty).midpoint(4.0), 3.5); - $fassert!((-3.0 as $fty).midpoint(4.0), 0.5); - $fassert!((3.0 as $fty).midpoint(-4.0), -0.5); - $fassert!((-3.0 as $fty).midpoint(-4.0), -3.5); - $fassert!((0.0 as $fty).midpoint(0.0), 0.0); - $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); - $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN), 0.0); - $fassert!(<$fty>::MIN.midpoint(<$fty>::MAX), -0.0); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!(<$fty>::MAX.midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); - $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MAX), <$fty>::MAX); - $fassert!( - (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), - <$fty>::MIN_POSITIVE - ); - $fassert!( - (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), - -<$fty>::MIN_POSITIVE - ); - $fassert!(<$fty>::MAX.midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); - $fassert!(<$fty>::MAX.midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); - $fassert!(<$fty>::INFINITY.midpoint(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!( - <$fty>::NEG_INFINITY.midpoint(<$fty>::NEG_INFINITY), - <$fty>::NEG_INFINITY - ); - $fassert!(<$fty>::NAN.midpoint(1.0).is_nan()); - $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.midpoint(<$fty>::NAN).is_nan()); - - // test if large differences in magnitude are still correctly computed. - // NOTE: that because of how small x and y are, x + y can never overflow - // so (x + y) / 2.0 is always correct - // in particular, `2.pow(i)` will never be at the max exponent, so it could - // be safely doubled, while j is significantly smaller. - for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { - for j in 0..64u8 { - let large = (2.0 as $fty).powi(i); - // a much smaller number, such that there is no chance of overflow to test - // potential double rounding in midpoint's implementation. - let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) - * <$fty>::EPSILON - * <$fty>::from(j); - - let naive = (large + small) / 2.0; - let midpoint = large.midpoint(small); - - assert_eq!(naive, midpoint); - } - } - } - #[test] - fn abs() { - $fassert!((-1.0 as $fty).abs(), 1.0); - $fassert!((1.0 as $fty).abs(), 1.0); - $fassert!(<$fty>::NEG_INFINITY.abs(), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.abs(), <$fty>::INFINITY); - } - #[test] - fn copysign() { - $fassert!((1.0 as $fty).copysign(-2.0), -1.0); - $fassert!((-1.0 as $fty).copysign(2.0), 1.0); - $fassert!(<$fty>::INFINITY.copysign(-0.0), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.copysign(0.0), <$fty>::INFINITY); - } - #[test] - fn rem_euclid() { - // FIXME: Use $fassert when rem_euclid becomes const - assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); - assert_eq!((42.0 as $fty).rem_euclid(<$fty>::INFINITY), (42.0 as $fty)); - assert!((42.0 as $fty).rem_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::INFINITY.rem_euclid(<$fty>::INFINITY).is_nan()); - assert!(<$fty>::INFINITY.rem_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::NAN.rem_euclid(<$fty>::INFINITY).is_nan()); - } - #[test] - fn div_euclid() { - // FIXME: Use $fassert when div_euclid becomes const - assert_eq!((42.0 as $fty).div_euclid(<$fty>::INFINITY), 0.0); - assert!((42.0 as $fty).div_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::INFINITY.div_euclid(<$fty>::INFINITY).is_nan()); - assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); - } - #[test] - fn floor() { - $fassert!((0.0 as $fty).floor(), 0.0); - $fassert!((0.0 as $fty).floor().is_sign_positive()); - $fassert!((-0.0 as $fty).floor(), -0.0); - $fassert!((-0.0 as $fty).floor().is_sign_negative()); - $fassert!((0.5 as $fty).floor(), 0.0); - $fassert!((-0.5 as $fty).floor(), -1.0); - $fassert!((1.5 as $fty).floor(), 1.0); - $fassert!(<$fty>::MAX.floor(), <$fty>::MAX); - $fassert!(<$fty>::MIN.floor(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.floor(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).floor(), -1.0); - $fassert!(<$fty>::NAN.floor().is_nan()); - $fassert!(<$fty>::INFINITY.floor(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.floor(), <$fty>::NEG_INFINITY); - } - #[test] - fn ceil() { - $fassert!((0.0 as $fty).ceil(), 0.0); - $fassert!((0.0 as $fty).ceil().is_sign_positive()); - $fassert!((-0.0 as $fty).ceil(), 0.0); - $fassert!((-0.0 as $fty).ceil().is_sign_negative()); - $fassert!((0.5 as $fty).ceil(), 1.0); - $fassert!((-0.5 as $fty).ceil(), 0.0); - $fassert!(<$fty>::MAX.ceil(), <$fty>::MAX); - $fassert!(<$fty>::MIN.ceil(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.ceil(), 1.0); - $fassert!((-<$fty>::MIN_POSITIVE).ceil(), 0.0); - $fassert!(<$fty>::NAN.ceil().is_nan()); - $fassert!(<$fty>::INFINITY.ceil(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.ceil(), <$fty>::NEG_INFINITY); - } - #[test] - fn round() { - $fassert!((0.0 as $fty).round(), 0.0); - $fassert!((0.0 as $fty).round().is_sign_positive()); - $fassert!((-0.0 as $fty).round(), -0.0); - $fassert!((-0.0 as $fty).round().is_sign_negative()); - $fassert!((0.5 as $fty).round(), 1.0); - $fassert!((-0.5 as $fty).round(), -1.0); - $fassert!(<$fty>::MAX.round(), <$fty>::MAX); - $fassert!(<$fty>::MIN.round(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.round(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).round(), 0.0); - $fassert!(<$fty>::NAN.round().is_nan()); - $fassert!(<$fty>::INFINITY.round(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.round(), <$fty>::NEG_INFINITY); - } - #[test] - fn round_ties_even() { - $fassert!((0.0 as $fty).round_ties_even(), 0.0); - $fassert!((0.0 as $fty).round_ties_even().is_sign_positive()); - $fassert!((-0.0 as $fty).round_ties_even(), -0.0); - $fassert!((-0.0 as $fty).round_ties_even().is_sign_negative()); - $fassert!((0.5 as $fty).round_ties_even(), 0.0); - $fassert!((0.5 as $fty).round_ties_even().is_sign_positive()); - $fassert!((-0.5 as $fty).round_ties_even(), -0.0); - $fassert!((-0.5 as $fty).round_ties_even().is_sign_negative()); - $fassert!(<$fty>::MAX.round_ties_even(), <$fty>::MAX); - $fassert!(<$fty>::MIN.round_ties_even(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.round_ties_even(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).round_ties_even(), 0.0); - $fassert!(<$fty>::NAN.round_ties_even().is_nan()); - $fassert!(<$fty>::INFINITY.round_ties_even(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.round_ties_even(), <$fty>::NEG_INFINITY); - } - #[test] - fn trunc() { - $fassert!((0.0 as $fty).trunc(), 0.0); - $fassert!((0.0 as $fty).trunc().is_sign_positive()); - $fassert!((-0.0 as $fty).trunc(), -0.0); - $fassert!((-0.0 as $fty).trunc().is_sign_negative()); - $fassert!((0.5 as $fty).trunc(), 0.0); - $fassert!((0.5 as $fty).trunc().is_sign_positive()); - $fassert!((-0.5 as $fty).trunc(), -0.0); - $fassert!((-0.5 as $fty).trunc().is_sign_negative()); - $fassert!(<$fty>::MAX.trunc(), <$fty>::MAX); - $fassert!(<$fty>::MIN.trunc(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.trunc(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).trunc(), 0.0); - $fassert!(<$fty>::NAN.trunc().is_nan()); - $fassert!(<$fty>::INFINITY.trunc(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.trunc(), <$fty>::NEG_INFINITY); - } - #[test] - fn fract() { - $fassert!((0.0 as $fty).fract(), 0.0); - $fassert!((0.0 as $fty).fract().is_sign_positive()); - $fassert!((-0.0 as $fty).fract(), 0.0); - $fassert!((-0.0 as $fty).fract().is_sign_positive()); - $fassert!((0.5 as $fty).fract(), 0.5); - $fassert!((0.5 as $fty).fract().is_sign_positive()); - $fassert!((-0.5 as $fty).fract(), -0.5); - $fassert!((-0.5 as $fty).fract().is_sign_negative()); - $fassert!(<$fty>::MAX.fract(), 0.0); - $fassert!(<$fty>::MIN.fract(), 0.0); - $fassert!(<$fty>::MIN_POSITIVE.fract(), <$fty>::MIN_POSITIVE); - $fassert!(<$fty>::MIN_POSITIVE.fract().is_sign_positive()); - $fassert!((-<$fty>::MIN_POSITIVE).fract(), -<$fty>::MIN_POSITIVE); - $fassert!((-<$fty>::MIN_POSITIVE).fract().is_sign_negative()); - $fassert!(<$fty>::NAN.fract().is_nan()); - $fassert!(<$fty>::INFINITY.fract().is_nan()); - $fassert!(<$fty>::NEG_INFINITY.fract().is_nan()); - } - } - }; -} - -// Custom assert macro that distribute between assert! and assert_eq! in a non-const context -macro_rules! float_assert { - ($b:expr) => { - assert!($b); - }; - ($left:expr, $right:expr) => { - assert_eq!($left, $right); - }; -} - -// Custom assert macro that only uses assert! in a const context -macro_rules! float_const_assert { - ($b:expr) => { - assert!(const { $b }); - }; - ($left:expr, $right:expr) => { - assert!(const { $left == $right }); - }; -} - -test_float!(f32, float_assert, f32); -test_float!(f32_const, float_const_assert, f32); -test_float!(f64, float_assert, f64); -test_float!(f64_const, float_const_assert, f64); From b1acf6217ab47227a7401d2305315adc014e0664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 5 Jun 2025 13:13:59 +0200 Subject: [PATCH 3/9] Check documentation of bootstrap in PR CI --- src/ci/docker/host-x86_64/mingw-check-2/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile index 11a66a1c01321..a1d04bd984c6e 100644 --- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile @@ -30,6 +30,7 @@ ENV SCRIPT \ python3 ../x.py check && \ python3 ../x.py clippy ci && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ + python3 ../x.py doc --stage 0 bootstrap && \ # Build both public and internal documentation. RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library && \ From 523cf1291bb260fffb428227821edba6b0f83eb7 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Fri, 6 Jun 2025 10:35:38 +0200 Subject: [PATCH 4/9] add solaris targets to build-manifest --- src/tools/build-manifest/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 741d7e3fa16c1..f8209f2c8cd29 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -40,7 +40,9 @@ static HOSTS: &[&str] = &[ "powerpc64le-unknown-linux-musl", "riscv64gc-unknown-linux-gnu", "s390x-unknown-linux-gnu", + "sparcv9-sun-solaris", "x86_64-apple-darwin", + "x86_64-pc-solaris", "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", "x86_64-unknown-freebsd", From b25aa2629892a71cd81c822e9ef4a07249aeb89d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 30 May 2025 14:40:44 -0700 Subject: [PATCH 5/9] compiler: set Apple frame pointers by architecture Apple targets can now overriding this configuration and instead use the default based on their architecture, which means aarch64 targets now have less frame pointers in leaf functions. --- compiler/rustc_target/src/spec/base/apple/mod.rs | 8 +++++++- .../src/spec/targets/aarch64_apple_darwin.rs | 3 +-- .../rustc_target/src/spec/targets/aarch64_apple_ios.rs | 3 +-- .../src/spec/targets/aarch64_apple_ios_macabi.rs | 3 +-- .../src/spec/targets/aarch64_apple_ios_sim.rs | 3 +-- .../rustc_target/src/spec/targets/aarch64_apple_tvos.rs | 3 +-- .../src/spec/targets/aarch64_apple_tvos_sim.rs | 3 +-- .../src/spec/targets/aarch64_apple_visionos.rs | 3 +-- .../src/spec/targets/aarch64_apple_visionos_sim.rs | 3 +-- .../src/spec/targets/aarch64_apple_watchos_sim.rs | 3 +-- .../rustc_target/src/spec/targets/arm64e_apple_darwin.rs | 3 +-- .../rustc_target/src/spec/targets/arm64e_apple_ios.rs | 3 +-- .../rustc_target/src/spec/targets/arm64e_apple_tvos.rs | 3 +-- .../rustc_target/src/spec/targets/i686_apple_darwin.rs | 9 ++------- .../rustc_target/src/spec/targets/x86_64_apple_darwin.rs | 3 +-- .../src/spec/targets/x86_64h_apple_darwin.rs | 3 +-- 16 files changed, 23 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 46fcd7d5c5198..aa6d1ec7009e7 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -124,7 +124,13 @@ pub(crate) fn base( // to v4, so we do the same. // https://github.com/llvm/llvm-project/blob/378778a0d10c2f8d5df8ceff81f95b6002984a4b/clang/lib/Driver/ToolChains/Darwin.cpp#L1203 default_dwarf_version: 4, - frame_pointer: FramePointer::Always, + frame_pointer: match arch { + // clang ignores `-fomit-frame-pointer` for Armv7, it only accepts `-momit-leaf-frame-pointer` + Armv7k | Armv7s => FramePointer::Always, + // clang supports omitting frame pointers for the rest, but... don't? + Arm64 | Arm64e | Arm64_32 => FramePointer::NonLeaf, + I386 | I686 | X86_64 | X86_64h => FramePointer::Always, + }, has_rpath: true, dll_suffix: ".dylib".into(), archive_format: "darwin".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index 6587abb2ba7e4..4dd39877715a7 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::Arm64, TargetAbi::Normal); @@ -17,7 +17,6 @@ pub(crate) fn target() -> Target { arch, options: TargetOptions { mcount: "\u{1}mcount".into(), - frame_pointer: FramePointer::NonLeaf, cpu: "apple-m1".into(), max_atomic_width: Some(128), // FIXME: The leak sanitizer currently fails the tests, see #88132. diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index 183a6c6f2d720..769a7b6c3919e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index ce9ae03e6999d..4bb2f73e4f9fd 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::MacCatalyst); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index 4405e3fec0288..7d04034e759b4 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index 037685db1b382..ec92a40e255fb 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index a386220e6fc5b..74fbe5a89ca7c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("tvos", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs index 2c1dfdd55ed15..dc595fbe7b6c1 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs index c0b8b409797b7..06ff1bfb2f071 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("visionos", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index 62968f5b55551..bad9f6c1485c8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("watchos", Arch::Arm64, TargetAbi::Simulator); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 79b95dbde52dc..326f2b16d594f 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::Arm64e, TargetAbi::Normal); @@ -17,7 +17,6 @@ pub(crate) fn target() -> Target { arch, options: TargetOptions { mcount: "\u{1}mcount".into(), - frame_pointer: FramePointer::NonLeaf, cpu: "apple-m1".into(), max_atomic_width: Some(128), // FIXME: The leak sanitizer currently fails the tests, see #88132. diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index 848dbeec199a4..01c6f0b888d65 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("ios", Arch::Arm64e, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12,+v8.3a,+pauth".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD, ..opts }, diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs index 3dbe169e826b0..cad3650bda1a4 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_tvos.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("tvos", Arch::Arm64e, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12,+v8.3a,+pauth".into(), max_atomic_width: Some(128), - frame_pointer: FramePointer::NonLeaf, ..opts }, } diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index 161db9a08bb03..d1339c57b0088 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, Target, TargetMetadata, TargetOptions}; +use crate::spec::{Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); @@ -16,11 +16,6 @@ pub(crate) fn target() -> Target { i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), arch, - options: TargetOptions { - mcount: "\u{1}mcount".into(), - max_atomic_width: Some(64), - frame_pointer: FramePointer::Always, - ..opts - }, + options: TargetOptions { mcount: "\u{1}mcount".into(), max_atomic_width: Some(64), ..opts }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 64c1705478054..eba595ba7dd24 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,5 +1,5 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); @@ -18,7 +18,6 @@ pub(crate) fn target() -> Target { options: TargetOptions { mcount: "\u{1}mcount".into(), max_atomic_width: Some(128), // penryn+ supports cmpxchg16b - frame_pointer: FramePointer::Always, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index 11010b7d92f81..e64556c4132ab 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,10 +1,9 @@ use crate::spec::base::apple::{Arch, TargetAbi, base}; -use crate::spec::{FramePointer, SanitizerSet, Target, TargetMetadata, TargetOptions}; +use crate::spec::{SanitizerSet, Target, TargetMetadata, TargetOptions}; pub(crate) fn target() -> Target { let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal); opts.max_atomic_width = Some(128); - opts.frame_pointer = FramePointer::Always; opts.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; From eba3a6106728e131286e3751459fccd7594102ef Mon Sep 17 00:00:00 2001 From: schvv31n Date: Tue, 4 Mar 2025 21:29:45 +0000 Subject: [PATCH 6/9] Stabilised `os_string_pathbuf_leak` --- library/std/src/ffi/os_str.rs | 2 +- library/std/src/path.rs | 2 +- library/std/tests/path.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 21d5b7292e819..3cc225004ea39 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -568,7 +568,7 @@ impl OsString { /// However, keep in mind that trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_os_str`]: Self::into_boxed_os_str - #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[stable(feature = "os_string_pathbuf_leak", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn leak<'a>(self) -> &'a mut OsStr { OsStr::from_inner_mut(self.inner.leak()) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 014b56d28f443..826d9f0f39dc6 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1252,7 +1252,7 @@ impl PathBuf { /// However, keep in mind that trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_path`]: Self::into_boxed_path - #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[stable(feature = "os_string_pathbuf_leak", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn leak<'a>(self) -> &'a mut Path { Path::from_inner_mut(self.inner.leak()) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 781855a2d14aa..be0dda1d426f3 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -3,7 +3,6 @@ path_add_extension, path_file_prefix, maybe_uninit_slice, - os_string_pathbuf_leak, normalize_lexically )] From 24dcfaf71ffe08a0b5acfcc5b5b4d2419e79b847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 6 Jun 2025 19:39:48 +0000 Subject: [PATCH 7/9] Make cast suggestions verbose ``` error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | LL | 1u32 as char; | ^^^^^^^^^^^^ invalid cast | help: try `char::from_u32` instead | LL - 1u32 as char; LL + char::from_u32(1u32); | ``` ``` error[E0620]: cast to unsized type: `&[u8]` as `[char]` --> $DIR/cast-to-slice.rs:6:5 | LL | arr as [char]; | ^^^^^^^^^^^^^ | help: try casting to a reference instead | LL | arr as &[char]; | + ``` ``` error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | LL | Box::new(1) as dyn Send; | ^^^^^^^^^^^^^^^^^^^^^^^ | help: you can cast to a `Box` instead | LL | Box::new(1) as Box; | ++++ + ``` --- compiler/rustc_hir_typeck/src/cast.rs | 105 +++++++----------- tests/ui/cast/cast-to-slice.stderr | 18 ++- ...-to-unsized-trait-object-suggestion.stderr | 18 ++- tests/ui/coercion/issue-73886.stderr | 3 +- .../coercion/non-primitive-cast-135412.stderr | 6 +- tests/ui/error-codes/E0604.stderr | 11 +- tests/ui/error-codes/E0620.stderr | 9 +- tests/ui/error-emitter/error-festival.stderr | 11 +- tests/ui/issues/issue-16048.stderr | 8 +- tests/ui/issues/issue-17441.stderr | 18 ++- tests/ui/mismatched_types/cast-rfc0401.stderr | 11 +- tests/ui/nonscalar-cast.stderr | 8 +- tests/ui/tag-variant-cast-non-nullary.stderr | 8 +- 13 files changed, 122 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index e144a6ab5999a..3884691cbbde5 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -380,16 +380,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.span_label(self.span, "invalid cast"); if self.expr_ty.is_numeric() { if self.expr_ty == fcx.tcx.types.u32 { - match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { - Ok(snippet) => err.span_suggestion( - self.span, - "try `char::from_u32` instead", - format!("char::from_u32({snippet})"), - Applicability::MachineApplicable, - ), - - Err(_) => err.span_help(self.span, "try `char::from_u32` instead"), - }; + err.multipart_suggestion( + "try `char::from_u32` instead", + vec![ + (self.expr_span.shrink_to_lo(), "char::from_u32(".to_string()), + (self.expr_span.shrink_to_hi().to(self.cast_span), ")".to_string()), + ], + Applicability::MachineApplicable, + ); } else if self.expr_ty == fcx.tcx.types.i8 { err.span_help(self.span, "try casting from `u8` instead"); } else { @@ -494,11 +492,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.cast_ty.kind(), ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) ) { - let mut label = true; // Check `impl From for self.cast_ty {}` for accurate suggestion: - if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) - && let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) - { + if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { let ty = fcx.resolve_vars_if_possible(self.cast_ty); let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); if fcx @@ -506,26 +501,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { .type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env) .must_apply_modulo_regions() { - label = false; - if let ty::Adt(def, args) = self.cast_ty.kind() { - err.span_suggestion_verbose( - self.span, - "consider using the `From` trait instead", - format!( - "{}::from({})", - fcx.tcx.value_path_str_with_args(def.did(), args), - snippet - ), - Applicability::MaybeIncorrect, - ); + let to_ty = if let ty::Adt(def, args) = self.cast_ty.kind() { + fcx.tcx.value_path_str_with_args(def.did(), args) } else { - err.span_suggestion( - self.span, - "consider using the `From` trait instead", - format!("{}::from({})", self.cast_ty, snippet), - Applicability::MaybeIncorrect, - ); + self.cast_ty.to_string() }; + err.multipart_suggestion( + "consider using the `From` trait instead", + vec![ + (self.expr_span.shrink_to_lo(), format!("{to_ty}::from(")), + ( + self.expr_span.shrink_to_hi().to(self.cast_span), + ")".to_string(), + ), + ], + Applicability::MaybeIncorrect, + ); } } @@ -548,11 +539,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) }; - if label { - err.span_label(self.span, msg); - } else { - err.note(msg); - } + err.span_label(self.span, msg); if let Some(note) = note { err.note(note); @@ -654,38 +641,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { match self.expr_ty.kind() { ty::Ref(_, _, mt) => { let mtstr = mt.prefix_str(); - match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) { - Ok(s) => { - err.span_suggestion( - self.cast_span, - "try casting to a reference instead", - format!("&{mtstr}{s}"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - let msg = format!("did you mean `&{mtstr}{tstr}`?"); - err.span_help(self.cast_span, msg); - } - } + err.span_suggestion_verbose( + self.cast_span.shrink_to_lo(), + "try casting to a reference instead", + format!("&{mtstr}"), + Applicability::MachineApplicable, + ); } ty::Adt(def, ..) if def.is_box() => { - match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) { - Ok(s) => { - err.span_suggestion( - self.cast_span, - "you can cast to a `Box` instead", - format!("Box<{s}>"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - err.span_help( - self.cast_span, - format!("you might have meant `Box<{tstr}>`"), - ); - } - } + err.multipart_suggestion( + "you can cast to a `Box` instead", + vec![ + (self.cast_span.shrink_to_lo(), "Box<".to_string()), + (self.cast_span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); } _ => { err.span_help(self.expr_span, "consider using a box or reference as appropriate"); diff --git a/tests/ui/cast/cast-to-slice.stderr b/tests/ui/cast/cast-to-slice.stderr index 8f862c0001401..1033f77ee0c6a 100644 --- a/tests/ui/cast/cast-to-slice.stderr +++ b/tests/ui/cast/cast-to-slice.stderr @@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]` --> $DIR/cast-to-slice.rs:2:5 | LL | "example".as_bytes() as [char]; - | ^^^^^^^^^^^^^^^^^^^^^^^^------ - | | - | help: try casting to a reference instead: `&[char]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | "example".as_bytes() as &[char]; + | + error[E0620]: cast to unsized type: `&[u8]` as `[char]` --> $DIR/cast-to-slice.rs:6:5 | LL | arr as [char]; - | ^^^^^^^------ - | | - | help: try casting to a reference instead: `&[char]` + | ^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | arr as &[char]; + | + error: aborting due to 2 previous errors diff --git a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index 3b5b8ea69c195..cc96055abebc8 100644 --- a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5 | LL | &1 as dyn Send; - | ^^^^^^-------- - | | - | help: try casting to a reference instead: `&dyn Send` + | ^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | &1 as &dyn Send; + | + error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | LL | Box::new(1) as dyn Send; - | ^^^^^^^^^^^^^^^-------- - | | - | help: you can cast to a `Box` instead: `Box` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you can cast to a `Box` instead + | +LL | Box::new(1) as Box; + | ++++ + error: aborting due to 2 previous errors diff --git a/tests/ui/coercion/issue-73886.stderr b/tests/ui/coercion/issue-73886.stderr index a287aa29e1183..891931d0bf89f 100644 --- a/tests/ui/coercion/issue-73886.stderr +++ b/tests/ui/coercion/issue-73886.stderr @@ -10,9 +10,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 | LL | let _ = 7u32 as Option<_>; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object help: consider using the `From` trait instead | LL - let _ = 7u32 as Option<_>; diff --git a/tests/ui/coercion/non-primitive-cast-135412.stderr b/tests/ui/coercion/non-primitive-cast-135412.stderr index 7e5861f83e9c1..e5e9ee134597d 100644 --- a/tests/ui/coercion/non-primitive-cast-135412.stderr +++ b/tests/ui/coercion/non-primitive-cast-135412.stderr @@ -2,9 +2,8 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/non-primitive-cast-135412.rs:6:13 | LL | let _ = 7u32 as Option<_>; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object help: consider using the `From` trait instead | LL - let _ = 7u32 as Option<_>; @@ -15,9 +14,8 @@ error[E0605]: non-primitive cast: `&'static str` as `Arc` --> $DIR/non-primitive-cast-135412.rs:8:13 | LL | let _ = "String" as Arc; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object help: consider using the `From` trait instead | LL - let _ = "String" as Arc; diff --git a/tests/ui/error-codes/E0604.stderr b/tests/ui/error-codes/E0604.stderr index e91f74d6b3fd6..b949ed973cdc2 100644 --- a/tests/ui/error-codes/E0604.stderr +++ b/tests/ui/error-codes/E0604.stderr @@ -2,10 +2,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | LL | 1u32 as char; - | ^^^^^^^^^^^^ - | | - | invalid cast - | help: try `char::from_u32` instead: `char::from_u32(1u32)` + | ^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + | +LL - 1u32 as char; +LL + char::from_u32(1u32); + | error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0620.stderr b/tests/ui/error-codes/E0620.stderr index 644ba813c9608..b2efe02f3aad0 100644 --- a/tests/ui/error-codes/E0620.stderr +++ b/tests/ui/error-codes/E0620.stderr @@ -2,9 +2,12 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` --> $DIR/E0620.rs:2:16 | LL | let _foo = &[1_usize, 2] as [usize]; - | ^^^^^^^^^^^^^^^^^------- - | | - | help: try casting to a reference instead: `&[usize]` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | let _foo = &[1_usize, 2] as &[usize]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/error-emitter/error-festival.stderr b/tests/ui/error-emitter/error-festival.stderr index be484bc8094fe..d2afae69c07bf 100644 --- a/tests/ui/error-emitter/error-festival.stderr +++ b/tests/ui/error-emitter/error-festival.stderr @@ -58,10 +58,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:27:5 | LL | 0u32 as char; - | ^^^^^^^^^^^^ - | | - | invalid cast - | help: try `char::from_u32` instead: `char::from_u32(0u32)` + | ^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + | +LL - 0u32 as char; +LL + char::from_u32(0u32); + | error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/error-festival.rs:31:5 diff --git a/tests/ui/issues/issue-16048.stderr b/tests/ui/issues/issue-16048.stderr index 73610942d7a7e..f97f13152bc83 100644 --- a/tests/ui/issues/issue-16048.stderr +++ b/tests/ui/issues/issue-16048.stderr @@ -11,9 +11,13 @@ error[E0605]: non-primitive cast: `Foo<'a>` as `T` --> $DIR/issue-16048.rs:24:16 | LL | return *self as T; - | ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)` + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | +help: consider using the `From` trait instead + | +LL - return *self as T; +LL + return T::from(*self); | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-17441.stderr b/tests/ui/issues/issue-17441.stderr index 29e50b91c7c6f..c96b13d62dcbb 100644 --- a/tests/ui/issues/issue-17441.stderr +++ b/tests/ui/issues/issue-17441.stderr @@ -2,17 +2,23 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` --> $DIR/issue-17441.rs:2:16 | LL | let _foo = &[1_usize, 2] as [usize]; - | ^^^^^^^^^^^^^^^^^------- - | | - | help: try casting to a reference instead: `&[usize]` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting to a reference instead + | +LL | let _foo = &[1_usize, 2] as &[usize]; + | + error[E0620]: cast to unsized type: `Box` as `dyn Debug` --> $DIR/issue-17441.rs:5:16 | LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^------------------- - | | - | help: you can cast to a `Box` instead: `Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you can cast to a `Box` instead + | +LL | let _bar = Box::new(1_usize) as Box; + | ++++ + error[E0620]: cast to unsized type: `usize` as `dyn Debug` --> $DIR/issue-17441.rs:8:16 diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index a427639594415..eb95d659840d7 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -104,10 +104,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/cast-rfc0401.rs:41:13 | LL | let _ = 0x61u32 as char; - | ^^^^^^^^^^^^^^^ - | | - | invalid cast - | help: try `char::from_u32` instead: `char::from_u32(0x61u32)` + | ^^^^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + | +LL - let _ = 0x61u32 as char; +LL + let _ = char::from_u32(0x61u32); + | error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:43:13 diff --git a/tests/ui/nonscalar-cast.stderr b/tests/ui/nonscalar-cast.stderr index 01b4a9a7ce026..834d4ea241c12 100644 --- a/tests/ui/nonscalar-cast.stderr +++ b/tests/ui/nonscalar-cast.stderr @@ -2,9 +2,13 @@ error[E0605]: non-primitive cast: `Foo` as `isize` --> $DIR/nonscalar-cast.rs:15:20 | LL | println!("{}", Foo { x: 1 } as isize); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })` + | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | +help: consider using the `From` trait instead + | +LL - println!("{}", Foo { x: 1 } as isize); +LL + println!("{}", isize::from(Foo { x: 1 })); | - = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 1 previous error diff --git a/tests/ui/tag-variant-cast-non-nullary.stderr b/tests/ui/tag-variant-cast-non-nullary.stderr index 2e1dde27d0f98..8ec1c5f11ec27 100644 --- a/tests/ui/tag-variant-cast-non-nullary.stderr +++ b/tests/ui/tag-variant-cast-non-nullary.stderr @@ -2,10 +2,14 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize` --> $DIR/tag-variant-cast-non-nullary.rs:19:15 | LL | let val = v as isize; - | ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)` + | ^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less | - = note: an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less = note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information +help: consider using the `From` trait instead + | +LL - let val = v as isize; +LL + let val = isize::from(v); + | error: aborting due to 1 previous error From ac980cace8038f3fa3be1953092e92bede52a5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 4 Jun 2025 21:39:29 +0000 Subject: [PATCH 8/9] Make obligation cause code suggestions verbose ``` error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:28:10 | LL | e!().await; | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` help: remove the `.await` | LL - e!().await; LL + e!(); | ``` ``` error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:1:47 | LL | static _MAYBE_STRINGS: [Option; 5] = [None; 5]; | ^^^^ the trait `Copy` is not implemented for `String` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array help: create an inline `const` block | LL | static _MAYBE_STRINGS: [Option; 5] = [const { None }; 5]; | +++++++ + ``` --- .../src/error_reporting/traits/suggestions.rs | 20 +++++++------- ...-ice-attempted-to-add-with-overflow.stderr | 10 ++++--- .../drop-track-bad-field-in-fru.stderr | 10 ++++--- tests/ui/async-await/issue-101715.stderr | 9 ++++--- tests/ui/async-await/unnecessary-await.stderr | 20 ++++++++------ .../const-blocks/fn-call-in-non-const.stderr | 5 ++-- .../ui/consts/const-blocks/trait-error.stderr | 9 ++++--- tests/ui/consts/const-fn-in-vec.stderr | 27 ++++++++++--------- tests/ui/coroutine/unresolved-ct-var.stderr | 11 +++++--- ...opy-check-when-count-inferred-later.stderr | 9 ++++--- .../constrain_in_projection2.next.stderr | 7 ++++- 11 files changed, 80 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c4f1f7d712a7c..aa113f3835bd9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1411,7 +1411,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - err.span_suggestion( + err.span_suggestion_verbose( obligation.cause.span.shrink_to_lo(), format!( "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`" @@ -1574,7 +1574,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .span_extend_while_whitespace(expr_span) .shrink_to_hi() .to(await_expr.span.shrink_to_hi()); - err.span_suggestion( + err.span_suggestion_verbose( removal_span, "remove the `.await`", "", @@ -2126,7 +2126,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )); if !assoc_item.is_impl_trait_in_trait() { - err.span_suggestion( + err.span_suggestion_verbose( span, "use the fully qualified path to an implementation", format!( @@ -2924,12 +2924,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let sm = tcx.sess.source_map(); if matches!(is_constable, IsConstable::Fn | IsConstable::Ctor) - && let Ok(snip) = sm.span_to_snippet(elt_span) + && let Ok(_) = sm.span_to_snippet(elt_span) { - err.span_suggestion( - elt_span, + err.multipart_suggestion( "create an inline `const` block", - format!("const {{ {snip} }}"), + vec![ + (elt_span.shrink_to_lo(), "const { ".to_string()), + (elt_span.shrink_to_hi(), " }".to_string()), + ], Applicability::MachineApplicable, ); } else { @@ -3127,13 +3129,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } err.help("change the field's type to have a statically known size"); - err.span_suggestion( + err.span_suggestion_verbose( span.shrink_to_lo(), "borrowed types always have a statically known size", "&", Applicability::MachineApplicable, ); - err.multipart_suggestion( + err.multipart_suggestion_verbose( "the `Box` type always has a statically known size and allocates its contents \ in the heap", vec![ diff --git a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr index 8c9d06c79ca42..40d44db205f79 100644 --- a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr +++ b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr @@ -2,14 +2,16 @@ error[E0277]: `[usize; usize::MAX]` is not a future --> $DIR/debug-ice-attempted-to-add-with-overflow.rs:8:37 | LL | [0usize; 0xffff_ffff_ffff_ffff].await; - | -^^^^^ - | || - | |`[usize; usize::MAX]` is not a future - | help: remove the `.await` + | ^^^^^ `[usize; usize::MAX]` is not a future | = help: the trait `Future` is not implemented for `[usize; usize::MAX]` = note: [usize; usize::MAX] must be a future or must implement `IntoFuture` to be awaited = note: required for `[usize; usize::MAX]` to implement `IntoFuture` +help: remove the `.await` + | +LL - [0usize; 0xffff_ffff_ffff_ffff].await; +LL + [0usize; 0xffff_ffff_ffff_ffff]; + | error[E0752]: `main` function is not allowed to be `async` --> $DIR/debug-ice-attempted-to-add-with-overflow.rs:6:1 diff --git a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr index 721e01062937e..644a7c7717ca9 100644 --- a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr +++ b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr @@ -10,14 +10,16 @@ error[E0277]: `Option<_>` is not a future --> $DIR/drop-track-bad-field-in-fru.rs:6:46 | LL | None { value: (), ..Default::default() }.await; - | -^^^^^ - | || - | |`Option<_>` is not a future - | help: remove the `.await` + | ^^^^^ `Option<_>` is not a future | = help: the trait `Future` is not implemented for `Option<_>` = note: Option<_> must be a future or must implement `IntoFuture` to be awaited = note: required for `Option<_>` to implement `IntoFuture` +help: remove the `.await` + | +LL - None { value: (), ..Default::default() }.await; +LL + None { value: (), ..Default::default() }; + | error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-101715.stderr b/tests/ui/async-await/issue-101715.stderr index f6af15c00d621..87302dce130e4 100644 --- a/tests/ui/async-await/issue-101715.stderr +++ b/tests/ui/async-await/issue-101715.stderr @@ -2,14 +2,15 @@ error[E0277]: `()` is not a future --> $DIR/issue-101715.rs:11:10 | LL | .await - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` +help: remove the `.await` + | +LL - .await + | error: aborting due to 1 previous error diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr index 620370a6113a3..f60b4ecb99098 100644 --- a/tests/ui/async-await/unnecessary-await.stderr +++ b/tests/ui/async-await/unnecessary-await.stderr @@ -23,14 +23,16 @@ error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:28:10 | LL | e!().await; - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` +help: remove the `.await` + | +LL - e!().await; +LL + e!(); + | error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:22:15 @@ -53,14 +55,16 @@ error[E0277]: `()` is not a future --> $DIR/unnecessary-await.rs:36:20 | LL | for x in [] {}.await - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` + | ^^^^^ `()` is not a future | = help: the trait `Future` is not implemented for `()` = note: () must be a future or must implement `IntoFuture` to be awaited = note: required for `()` to implement `IntoFuture` +help: remove the `.await` + | +LL - for x in [] {}.await +LL + for x in [] {} + | error: aborting due to 4 previous errors diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr index a3d5054ced358..54982391b6652 100644 --- a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr +++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr @@ -13,9 +13,8 @@ LL | struct Bar; | help: create an inline `const` block | -LL - let _: [Option; 2] = [no_copy(); 2]; -LL + let _: [Option; 2] = [const { no_copy() }; 2]; - | +LL | let _: [Option; 2] = [const { no_copy() }; 2]; + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-blocks/trait-error.stderr b/tests/ui/consts/const-blocks/trait-error.stderr index 58ddc047d03a5..601d067e3d849 100644 --- a/tests/ui/consts/const-blocks/trait-error.stderr +++ b/tests/ui/consts/const-blocks/trait-error.stderr @@ -2,10 +2,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trait-error.rs:5:6 | LL | [Foo(String::new()); 4]; - | ^^^^^^^^^^^^^^^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { Foo(String::new()) }` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | note: required for `Foo` to implement `Copy` --> $DIR/trait-error.rs:1:10 @@ -13,6 +10,10 @@ note: required for `Foo` to implement `Copy` LL | #[derive(Copy, Clone)] | ^^^^ unsatisfied trait bound introduced in this `derive` macro = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | [const { Foo(String::new()) }; 4]; + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-fn-in-vec.stderr b/tests/ui/consts/const-fn-in-vec.stderr index 5be26d7c121bb..890eb8040b943 100644 --- a/tests/ui/consts/const-fn-in-vec.stderr +++ b/tests/ui/consts/const-fn-in-vec.stderr @@ -2,36 +2,39 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:1:47 | LL | static _MAYBE_STRINGS: [Option; 5] = [None; 5]; - | ^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { None }` + | ^^^^ the trait `Copy` is not implemented for `String` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | static _MAYBE_STRINGS: [Option; 5] = [const { None }; 5]; + | +++++++ + error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:7:34 | LL | let _strings: [String; 5] = [String::new(); 5]; - | ^^^^^^^^^^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { String::new() }` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | let _strings: [String; 5] = [const { String::new() }; 5]; + | +++++++ + error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/const-fn-in-vec.rs:12:48 | LL | let _maybe_strings: [Option; 5] = [None; 5]; - | ^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { None }` + | ^^^^ the trait `Copy` is not implemented for `String` | = note: required for `Option` to implement `Copy` = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | let _maybe_strings: [Option; 5] = [const { None }; 5]; + | +++++++ + error: aborting due to 3 previous errors diff --git a/tests/ui/coroutine/unresolved-ct-var.stderr b/tests/ui/coroutine/unresolved-ct-var.stderr index da2ec272f9fff..86b73e4b0629a 100644 --- a/tests/ui/coroutine/unresolved-ct-var.stderr +++ b/tests/ui/coroutine/unresolved-ct-var.stderr @@ -2,15 +2,18 @@ error[E0277]: `[(); _]` is not a future --> $DIR/unresolved-ct-var.rs:6:45 | LL | let s = std::array::from_fn(|_| ()).await; - | ----------------------------^^^^^ - | | || - | | |`[(); _]` is not a future - | | help: remove the `.await` + | --------------------------- ^^^^^ `[(); _]` is not a future + | | | this call returns `[(); _]` | = help: the trait `Future` is not implemented for `[(); _]` = note: [(); _] must be a future or must implement `IntoFuture` to be awaited = note: required for `[(); _]` to implement `IntoFuture` +help: remove the `.await` + | +LL - let s = std::array::from_fn(|_| ()).await; +LL + let s = std::array::from_fn(|_| ()); + | error: aborting due to 1 previous error diff --git a/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr index d974f5add5052..1c862f2b606a8 100644 --- a/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr +++ b/tests/ui/repeat-expr/copy-check-when-count-inferred-later.stderr @@ -2,12 +2,13 @@ error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/copy-check-when-count-inferred-later.rs:8:14 | LL | let a = [String::new(); _]; - | ^^^^^^^^^^^^^ - | | - | the trait `Copy` is not implemented for `String` - | help: create an inline `const` block: `const { String::new() }` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the `Copy` trait is required because this value will be copied for each element of the array +help: create an inline `const` block + | +LL | let a = [const { String::new() }; _]; + | +++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr index 7c09ab6a91ae9..72a253c4be813 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.next.stderr @@ -2,7 +2,7 @@ error[E0283]: type annotations needed: cannot satisfy `Foo: Trait` --> $DIR/constrain_in_projection2.rs:28:14 | LL | let x = >::Assoc::default(); - | ^^^ help: use the fully qualified path to an implementation: `::Assoc` + | ^^^ | note: multiple `impl`s satisfying `Foo: Trait` found --> $DIR/constrain_in_projection2.rs:18:1 @@ -13,6 +13,11 @@ LL | impl Trait<()> for Foo { LL | impl Trait for Foo { | ^^^^^^^^^^^^^^^^^^^^^^^ = note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` +help: use the fully qualified path to an implementation + | +LL - let x = >::Assoc::default(); +LL + let x = <::Assoc as Trait>::Assoc::default(); + | error: aborting due to 1 previous error From 3c049e21ca75134b7cab84507c93c18ce38ff275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 6 Jun 2025 20:52:34 +0000 Subject: [PATCH 9/9] reword suggestion message --- compiler/rustc_hir_typeck/src/cast.rs | 11 +++++++---- tests/ui/cast/cast-to-slice.stderr | 4 ++-- .../cast-to-unsized-trait-object-suggestion.stderr | 2 +- .../consts/const-eval/const-eval-overflow-4b.stderr | 2 +- tests/ui/error-codes/E0604.stderr | 2 +- tests/ui/error-codes/E0620.stderr | 2 +- tests/ui/error-emitter/error-festival.stderr | 2 +- tests/ui/issues/issue-17441.stderr | 2 +- tests/ui/mismatched_types/cast-rfc0401.stderr | 2 +- 9 files changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 3884691cbbde5..e17cfc15a43d2 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -381,7 +381,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { if self.expr_ty.is_numeric() { if self.expr_ty == fcx.tcx.types.u32 { err.multipart_suggestion( - "try `char::from_u32` instead", + "consider using `char::from_u32` instead", vec![ (self.expr_span.shrink_to_lo(), "char::from_u32(".to_string()), (self.expr_span.shrink_to_hi().to(self.cast_span), ")".to_string()), @@ -389,9 +389,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { Applicability::MachineApplicable, ); } else if self.expr_ty == fcx.tcx.types.i8 { - err.span_help(self.span, "try casting from `u8` instead"); + err.span_help(self.span, "consider casting from `u8` instead"); } else { - err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)"); + err.span_help( + self.span, + "consider using `char::from_u32` instead (via a `u32`)", + ); }; } err.emit(); @@ -643,7 +646,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let mtstr = mt.prefix_str(); err.span_suggestion_verbose( self.cast_span.shrink_to_lo(), - "try casting to a reference instead", + "consider casting to a reference instead", format!("&{mtstr}"), Applicability::MachineApplicable, ); diff --git a/tests/ui/cast/cast-to-slice.stderr b/tests/ui/cast/cast-to-slice.stderr index 1033f77ee0c6a..382ccc3d10c91 100644 --- a/tests/ui/cast/cast-to-slice.stderr +++ b/tests/ui/cast/cast-to-slice.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]` LL | "example".as_bytes() as [char]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | "example".as_bytes() as &[char]; | + @@ -15,7 +15,7 @@ error[E0620]: cast to unsized type: `&[u8]` as `[char]` LL | arr as [char]; | ^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | arr as &[char]; | + diff --git a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index cc96055abebc8..2803c3380d7ab 100644 --- a/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/tests/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&{integer}` as `dyn Send` LL | &1 as dyn Send; | ^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | &1 as &dyn Send; | + diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index 1a0832b8ba02b..b996370ea3dfd 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -23,7 +23,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8` LL | : [u32; 5i8 as char as usize] | ^^^^^^^^^^^ invalid cast | -help: try casting from `u8` instead +help: consider casting from `u8` instead --> $DIR/const-eval-overflow-4b.rs:24:13 | LL | : [u32; 5i8 as char as usize] diff --git a/tests/ui/error-codes/E0604.stderr b/tests/ui/error-codes/E0604.stderr index b949ed973cdc2..67bbb25958f12 100644 --- a/tests/ui/error-codes/E0604.stderr +++ b/tests/ui/error-codes/E0604.stderr @@ -4,7 +4,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | 1u32 as char; | ^^^^^^^^^^^^ invalid cast | -help: try `char::from_u32` instead +help: consider using `char::from_u32` instead | LL - 1u32 as char; LL + char::from_u32(1u32); diff --git a/tests/ui/error-codes/E0620.stderr b/tests/ui/error-codes/E0620.stderr index b2efe02f3aad0..696407c6f7e0d 100644 --- a/tests/ui/error-codes/E0620.stderr +++ b/tests/ui/error-codes/E0620.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | let _foo = &[1_usize, 2] as &[usize]; | + diff --git a/tests/ui/error-emitter/error-festival.stderr b/tests/ui/error-emitter/error-festival.stderr index d2afae69c07bf..6c661eb17a87b 100644 --- a/tests/ui/error-emitter/error-festival.stderr +++ b/tests/ui/error-emitter/error-festival.stderr @@ -60,7 +60,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | 0u32 as char; | ^^^^^^^^^^^^ invalid cast | -help: try `char::from_u32` instead +help: consider using `char::from_u32` instead | LL - 0u32 as char; LL + char::from_u32(0u32); diff --git a/tests/ui/issues/issue-17441.stderr b/tests/ui/issues/issue-17441.stderr index c96b13d62dcbb..96aad879e24d2 100644 --- a/tests/ui/issues/issue-17441.stderr +++ b/tests/ui/issues/issue-17441.stderr @@ -4,7 +4,7 @@ error[E0620]: cast to unsized type: `&[usize; 2]` as `[usize]` LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ | -help: try casting to a reference instead +help: consider casting to a reference instead | LL | let _foo = &[1_usize, 2] as &[usize]; | + diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index eb95d659840d7..a188b7791fdc8 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -106,7 +106,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | let _ = 0x61u32 as char; | ^^^^^^^^^^^^^^^ invalid cast | -help: try `char::from_u32` instead +help: consider using `char::from_u32` instead | LL - let _ = 0x61u32 as char; LL + let _ = char::from_u32(0x61u32);