From ad1d853ad99bf6da6c00ef7ed9baac223d569ffc Mon Sep 17 00:00:00 2001 From: Bee Date: Sun, 27 Sep 2026 17:59:07 +0100 Subject: [PATCH 01/29] Use a macro to reduce duplication in `core/src/num/f{16,32,64,128}.rs` (part 1) The macro is duplicated in each file to allow the diff to compare changes with the previous implementation. --- library/core/src/lib.rs | 6 +- library/core/src/num/f128.rs | 343 ++++++++++++++++---------- library/core/src/num/f16.rs | 345 +++++++++++++++++---------- library/core/src/num/f32.rs | 314 ++++++++++++++++-------- library/core/src/num/f64.rs | 315 ++++++++++++++++-------- library/core/src/num/float_macros.rs | 329 +++++++++++++++++++++++++ library/core/src/num/mod.rs | 1 + 7 files changed, 1184 insertions(+), 469 deletions(-) create mode 100644 library/core/src/num/float_macros.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d7d8d32ed88e7..002ff5b23ea7e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -252,6 +252,9 @@ pub use legacy_int_modules::{i8, i16, i32, i64, isize, u8, u16, u32, u64, usize} #[allow(deprecated, clippy::legacy_numeric_constants)] pub use legacy_int_modules::{i128, u128}; +#[macro_use] +pub mod num; + #[path = "num/f128.rs"] pub mod f128; #[path = "num/f16.rs"] @@ -261,9 +264,6 @@ pub mod f32; #[path = "num/f64.rs"] pub mod f64; -#[macro_use] -pub mod num; - /* Core modules for ownership management */ pub mod hint; diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index db05d7fdc5087..8f8a6af0aaccd 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -150,73 +150,107 @@ pub mod consts { pub const LN_10: f128 = 2.30258509299404568401799145468436420760110148862877297603333_f128; } -#[doc(test(attr( - feature(cfg_target_has_reliable_f16_f128), - allow(internal_features, unused_features) -)))] -impl f128 { - /// The radix or base of the internal representation of `f128`. - #[unstable(feature = "f128", issue = "116909")] +#[rustc_macro_transparency = "semiopaque"] +pub(crate) macro float_impl( + Self = $SelfT:ty, + Bits = $BitsT:ty, + SignedBits = $SignedBitsT:ty, + // Constants + BITS = $BITS:literal, + MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, + DIGITS = $DIGITS:literal, + EPSILON = $EPSILON:literal, + MIN = $MIN:literal, + MIN_POSITIVE = $MIN_POSITIVE:literal, + MAX = $MAX:literal, + MIN_EXP = $MIN_EXP:literal, + MAX_EXP = $MAX_EXP:literal, + MIN_10_EXP = $MIN_10_EXP:literal, + MAX_10_EXP = $MAX_10_EXP:literal, + SIGN_MASK = $SIGN_MASK:literal, + EXPONENT_MASK = $EXPONENT_MASK:literal, + MANTISSA_MASK = $MANTISSA_MASK:literal, + // Values for docs + exponent_bias = $exponent_bias:literal, + // Feature gates + assoc_int_consts = #[$assoc_int_consts:meta], + // Things needed for `f16`/`f128` doctests + $(feature = $feature:ident,)? + $(has_reliable_cfg = $has_reliable_cfg:ident,)? + $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? +) { + + /// The radix or base of the internal representation of + #[doc = concat!("`", stringify!($SelfT), "`.")] + #[$assoc_int_consts] pub const RADIX: u32 = 2; /// The size of this float type in bits. - // #[unstable(feature = "f128", issue = "116909")] #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = 128; + pub const BITS: u32 = $BITS; /// Number of significant digits in base 2. /// /// Note that the size of the mantissa in the bitwise representation is one /// smaller than this since the leading 1 is not stored explicitly. - #[unstable(feature = "f128", issue = "116909")] - pub const MANTISSA_DIGITS: u32 = 113; + #[$assoc_int_consts] + pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; /// Approximate number of significant digits in base 10. /// /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to `f128` and back without loss. + /// significant digits can be converted to + #[doc = concat!("`", stringify!($SelfT), "`")] + /// and back without loss. /// /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). /// - /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS - #[unstable(feature = "f128", issue = "116909")] - pub const DIGITS: u32 = 33; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + pub const DIGITS: u32 = $DIGITS; - /// [Machine epsilon] value for `f128`. + /// [Machine epsilon] value for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// /// This is the difference between `1.0` and the next larger representable number. /// /// Equal to 21 − [`MANTISSA_DIGITS`]. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS - #[unstable(feature = "f128", issue = "116909")] - #[rustc_diagnostic_item = "f128_epsilon"] - pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] + pub const EPSILON: Self = $EPSILON; - /// Smallest finite `f128` value. + /// Smallest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to −[`MAX`]. /// - /// [`MAX`]: f128::MAX - #[unstable(feature = "f128", issue = "116909")] - pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128; - /// Smallest positive normal `f128` value. + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MIN: Self = $MIN; + /// Smallest positive normal + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to 2[`MIN_EXP`] − 1. /// - /// [`MIN_EXP`]: f128::MIN_EXP - #[unstable(feature = "f128", issue = "116909")] - pub const MIN_POSITIVE: f128 = 3.36210314311209350626267781732175260e-4932_f128; - /// Largest finite `f128` value. + /// [`MIN_EXP`]: Self::MIN_EXP + #[$assoc_int_consts] + pub const MIN_POSITIVE: Self = $MIN_POSITIVE; + /// Largest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. /// - /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS - /// [`MAX_EXP`]: f128::MAX_EXP - #[unstable(feature = "f128", issue = "116909")] - pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + /// [`MAX_EXP`]: Self::MAX_EXP + #[$assoc_int_consts] + pub const MAX: Self = $MAX; /// One greater than the minimum possible *normal* power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). @@ -225,8 +259,8 @@ impl f128 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all normal numbers representable by this type are /// greater than or equal to 0.5 × 2MIN_EXP. - #[unstable(feature = "f128", issue = "116909")] - pub const MIN_EXP: i32 = -16_381; + #[$assoc_int_consts] + pub const MIN_EXP: i32 = $MIN_EXP; /// One greater than the maximum possible power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// @@ -234,23 +268,23 @@ impl f128 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all numbers representable by this type are /// strictly less than 2MAX_EXP. - #[unstable(feature = "f128", issue = "116909")] - pub const MAX_EXP: i32 = 16_384; + #[$assoc_int_consts] + pub const MAX_EXP: i32 = $MAX_EXP; /// Minimum x for which 10x is normal. /// /// Equal to ceil(log10 [`MIN_POSITIVE`]). /// - /// [`MIN_POSITIVE`]: f128::MIN_POSITIVE - #[unstable(feature = "f128", issue = "116909")] - pub const MIN_10_EXP: i32 = -4_931; + /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE + #[$assoc_int_consts] + pub const MIN_10_EXP: i32 = $MIN_10_EXP; /// Maximum x for which 10x is normal. /// /// Equal to floor(log10 [`MAX`]). /// - /// [`MAX`]: f128::MAX - #[unstable(feature = "f128", issue = "116909")] - pub const MAX_10_EXP: i32 = 4_932; + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MAX_10_EXP: i32 = $MAX_10_EXP; /// Not a Number (NaN). /// @@ -264,161 +298,216 @@ impl f128 { /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. /// The concrete bit pattern may change across Rust versions and target platforms. - #[allow(clippy::eq_op)] - #[rustc_diagnostic_item = "f128_nan"] - #[unstable(feature = "f128", issue = "116909")] - pub const NAN: f128 = 0.0_f128 / 0.0_f128; - + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] + #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] + pub const NAN: Self = 0.0 / 0.0; /// Infinity (∞). - #[unstable(feature = "f128", issue = "116909")] - pub const INFINITY: f128 = 1.0_f128 / 0.0_f128; - + #[$assoc_int_consts] + pub const INFINITY: Self = 1.0 / 0.0; /// Negative infinity (−∞). - #[unstable(feature = "f128", issue = "116909")] - pub const NEG_INFINITY: f128 = -1.0_f128 / 0.0_f128; + #[$assoc_int_consts] + pub const NEG_INFINITY: Self = -1.0 / 0.0; - /// Maximum integer that can be represented exactly in an [`f128`] value, - /// with no other integer converting to the same floating point value. + /// Maximum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i128`] and [`f128`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to - /// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// - /// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` - /// #![feature(f128)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// # #[cfg(target_has_reliable_f128)] { - /// let max_exact_int = f128::MAX_EXACT_INTEGER; - /// assert_eq!(max_exact_int, max_exact_int as f128 as i128); - /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f128 as i128); - /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f128 as i128); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Beyond `f128::MAX_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((max_exact_int + 1) as f128, (max_exact_int + 2) as f128); - /// # }} + #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` - // #[unstable(feature = "f128", issue = "116909")] #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: i128 = (1 << Self::MANTISSA_DIGITS) - 1; + pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - /// Minimum integer that can be represented exactly in an [`f128`] value, - /// with no other integer converting to the same floating point value. + /// Minimum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i128`] and [`f128`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to - /// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// /// This constant is equivalent to `-MAX_EXACT_INTEGER`. /// - /// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` - /// #![feature(f128)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// # #[cfg(target_has_reliable_f128)] { - /// let min_exact_int = f128::MIN_EXACT_INTEGER; - /// assert_eq!(min_exact_int, min_exact_int as f128 as i128); - /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f128 as i128); - /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f128 as i128); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Below `f128::MIN_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((min_exact_int - 1) as f128, (min_exact_int - 2) as f128); - /// # }} + #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` - // #[unstable(feature = "f128", issue = "116909")] #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER; + pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - /// The mask of the bit used to encode the sign of an [`f128`]. + /// The mask of the bit used to encode the sign of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// This bit is set when the sign is negative and unset when the sign is /// positive. /// If you only need to check whether a value is positive or negative, /// [`is_sign_positive`] or [`is_sign_negative`] can be used. /// - /// [`is_sign_positive`]: f128::is_sign_positive - /// [`is_sign_negative`]: f128::is_sign_negative - /// ```rust + /// [`is_sign_positive`]: Self::is_sign_positive + /// [`is_sign_negative`]: Self::is_sign_negative + /// ``` /// #![feature(float_masks)] - /// #![feature(f128)] - /// # #[cfg(target_has_reliable_f128)] { - /// let sign_mask = f128::SIGN_MASK; - /// let a = 1.6552f128; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let a_bits = a.to_bits(); /// /// assert_eq!(a_bits & sign_mask, 0x0); - /// assert_eq!(f128::from_bits(a_bits ^ sign_mask), -a); - /// assert_eq!(sign_mask, (-0.0f128).to_bits()); - /// # } + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] + #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + pub const SIGN_MASK: $BitsT = $SIGN_MASK; - /// The mask of the bits used to encode the exponent of an [`f128`]. + /// The mask of the bits used to encode the exponent of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// - /// Note that the exponent is stored as a biased value, with a bias of 16383 for `f128`. + /// Note that the exponent is stored as a biased value, with a bias of + #[doc = stringify!($exponent_bias)] + /// for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// - /// ```rust + /// ``` /// #![feature(float_masks)] - /// #![feature(f128)] - /// # #[cfg(target_has_reliable_f128)] { - /// fn get_exp(a: f128) -> i128 { - /// let bias = 16383; - /// let biased = a.to_bits() & f128::EXPONENT_MASK; - /// (biased >> (f128::MANTISSA_DIGITS - 1)).cast_signed() - bias + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] + #[doc = concat!(" let bias = ", $exponent_bias, ";")] + #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] + #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] /// } /// /// assert_eq!(get_exp(0.5), -1); /// assert_eq!(get_exp(1.0), 0); /// assert_eq!(get_exp(2.0), 1); /// assert_eq!(get_exp(4.0), 2); - /// # } + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000; + pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - /// The mask of the bits used to encode the mantissa of an [`f128`]. + /// The mask of the bits used to encode the mantissa of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// ```rust /// #![feature(float_masks)] - /// #![feature(f128)] - /// # #[cfg(target_has_reliable_f128)] { - /// let mantissa_mask = f128::MANTISSA_MASK; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] /// - /// assert_eq!(0f128.to_bits() & mantissa_mask, 0x0); - /// assert_eq!(1f128.to_bits() & mantissa_mask, 0x0); + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] /// /// // multiplying a finite value by a power of 2 doesn't change its mantissa /// // unless the result or initial value is not normal. - /// let a = 1.6552f128; + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let b = 4.0 * a; /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); /// /// // The maximum and minimum values have a saturated significand - /// assert_eq!(f128::MAX.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK); - /// assert_eq!(f128::MIN.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK); - /// # } + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff; + pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; /// Minimum representable positive value (min subnormal) - const TINY_BITS: u128 = 0x1; + const TINY_BITS: $BitsT = 0x1; /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: u128 = Self::TINY_BITS | Self::SIGN_MASK; + const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; +} + +#[doc(test(attr( + feature(cfg_target_has_reliable_f16_f128), + allow(internal_features, unused_features) +)))] +impl f128 { + float_impl! { + Self = f128, + Bits = u128, + SignedBits = i128, + BITS = 128, + MANTISSA_DIGITS = 113, + DIGITS = 33, + EPSILON = 1.92592994438723585305597794258492732e-34_f128, + MIN = -1.18973149535723176508575932662800702e+4932_f128, + MIN_POSITIVE = 3.36210314311209350626267781732175260e-4932_f128, + MAX = 1.18973149535723176508575932662800702e+4932_f128, + MIN_EXP = -16_381, + MAX_EXP = 16_384, + MIN_10_EXP = -4_931, + MAX_10_EXP = 4_932, + SIGN_MASK = 0x8000_0000_0000_0000_0000_0000_0000_0000, + EXPONENT_MASK = 0x7fff_0000_0000_0000_0000_0000_0000_0000, + MANTISSA_MASK = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff, + exponent_bias = 16383, + assoc_int_consts = #[unstable(feature = "f128", issue = "116909")], + feature = f128, + has_reliable_cfg = target_has_reliable_f128, + has_reliable_math_cfg = target_has_reliable_f128_math, + } /// Returns `true` if this value is NaN. /// diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 273ef3688ca5f..48fe45402aeac 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -144,73 +144,107 @@ pub mod consts { pub const LN_10: f16 = 2.30258509299404568401799145468436421_f16; } -#[doc(test(attr( - feature(cfg_target_has_reliable_f16_f128), - allow(internal_features, unused_features) -)))] -impl f16 { - /// The radix or base of the internal representation of `f16`. - #[unstable(feature = "f16", issue = "116909")] +#[rustc_macro_transparency = "semiopaque"] +pub(crate) macro float_impl( + Self = $SelfT:ty, + Bits = $BitsT:ty, + SignedBits = $SignedBitsT:ty, + // Constants + BITS = $BITS:literal, + MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, + DIGITS = $DIGITS:literal, + EPSILON = $EPSILON:literal, + MIN = $MIN:literal, + MIN_POSITIVE = $MIN_POSITIVE:literal, + MAX = $MAX:literal, + MIN_EXP = $MIN_EXP:literal, + MAX_EXP = $MAX_EXP:literal, + MIN_10_EXP = $MIN_10_EXP:literal, + MAX_10_EXP = $MAX_10_EXP:literal, + SIGN_MASK = $SIGN_MASK:literal, + EXPONENT_MASK = $EXPONENT_MASK:literal, + MANTISSA_MASK = $MANTISSA_MASK:literal, + // Values for docs + exponent_bias = $exponent_bias:literal, + // Feature gates + assoc_int_consts = #[$assoc_int_consts:meta], + // Things needed for `f16`/`f128` doctests + $(feature = $feature:ident,)? + $(has_reliable_cfg = $has_reliable_cfg:ident,)? + $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? +) { + + /// The radix or base of the internal representation of + #[doc = concat!("`", stringify!($SelfT), "`.")] + #[$assoc_int_consts] pub const RADIX: u32 = 2; /// The size of this float type in bits. - // #[unstable(feature = "f16", issue = "116909")] #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = 16; + pub const BITS: u32 = $BITS; /// Number of significant digits in base 2. /// /// Note that the size of the mantissa in the bitwise representation is one /// smaller than this since the leading 1 is not stored explicitly. - #[unstable(feature = "f16", issue = "116909")] - pub const MANTISSA_DIGITS: u32 = 11; + #[$assoc_int_consts] + pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; /// Approximate number of significant digits in base 10. /// /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to `f16` and back without loss. + /// significant digits can be converted to + #[doc = concat!("`", stringify!($SelfT), "`")] + /// and back without loss. /// /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). /// - /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS - #[unstable(feature = "f16", issue = "116909")] - pub const DIGITS: u32 = 3; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + pub const DIGITS: u32 = $DIGITS; - /// [Machine epsilon] value for `f16`. + /// [Machine epsilon] value for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// /// This is the difference between `1.0` and the next larger representable number. /// /// Equal to 21 − [`MANTISSA_DIGITS`]. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS - #[unstable(feature = "f16", issue = "116909")] - #[rustc_diagnostic_item = "f16_epsilon"] - pub const EPSILON: f16 = 9.7656e-4_f16; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] + pub const EPSILON: Self = $EPSILON; - /// Smallest finite `f16` value. + /// Smallest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to −[`MAX`]. /// - /// [`MAX`]: f16::MAX - #[unstable(feature = "f16", issue = "116909")] - pub const MIN: f16 = -6.5504e+4_f16; - /// Smallest positive normal `f16` value. + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MIN: Self = $MIN; + /// Smallest positive normal + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to 2[`MIN_EXP`] − 1. /// - /// [`MIN_EXP`]: f16::MIN_EXP - #[unstable(feature = "f16", issue = "116909")] - pub const MIN_POSITIVE: f16 = 6.1035e-5_f16; - /// Largest finite `f16` value. + /// [`MIN_EXP`]: Self::MIN_EXP + #[$assoc_int_consts] + pub const MIN_POSITIVE: Self = $MIN_POSITIVE; + /// Largest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. /// - /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS - /// [`MAX_EXP`]: f16::MAX_EXP - #[unstable(feature = "f16", issue = "116909")] - pub const MAX: f16 = 6.5504e+4_f16; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + /// [`MAX_EXP`]: Self::MAX_EXP + #[$assoc_int_consts] + pub const MAX: Self = $MAX; /// One greater than the minimum possible *normal* power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). @@ -219,8 +253,8 @@ impl f16 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all normal numbers representable by this type are /// greater than or equal to 0.5 × 2MIN_EXP. - #[unstable(feature = "f16", issue = "116909")] - pub const MIN_EXP: i32 = -13; + #[$assoc_int_consts] + pub const MIN_EXP: i32 = $MIN_EXP; /// One greater than the maximum possible power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// @@ -228,23 +262,23 @@ impl f16 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all numbers representable by this type are /// strictly less than 2MAX_EXP. - #[unstable(feature = "f16", issue = "116909")] - pub const MAX_EXP: i32 = 16; + #[$assoc_int_consts] + pub const MAX_EXP: i32 = $MAX_EXP; /// Minimum x for which 10x is normal. /// /// Equal to ceil(log10 [`MIN_POSITIVE`]). /// - /// [`MIN_POSITIVE`]: f16::MIN_POSITIVE - #[unstable(feature = "f16", issue = "116909")] - pub const MIN_10_EXP: i32 = -4; + /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE + #[$assoc_int_consts] + pub const MIN_10_EXP: i32 = $MIN_10_EXP; /// Maximum x for which 10x is normal. /// /// Equal to floor(log10 [`MAX`]). /// - /// [`MAX`]: f16::MAX - #[unstable(feature = "f16", issue = "116909")] - pub const MAX_10_EXP: i32 = 4; + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MAX_10_EXP: i32 = $MAX_10_EXP; /// Not a Number (NaN). /// @@ -258,163 +292,216 @@ impl f16 { /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. /// The concrete bit pattern may change across Rust versions and target platforms. - #[allow(clippy::eq_op)] - #[rustc_diagnostic_item = "f16_nan"] - #[unstable(feature = "f16", issue = "116909")] - pub const NAN: f16 = 0.0_f16 / 0.0_f16; - + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] + #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] + pub const NAN: Self = 0.0 / 0.0; /// Infinity (∞). - #[unstable(feature = "f16", issue = "116909")] - pub const INFINITY: f16 = 1.0_f16 / 0.0_f16; - + #[$assoc_int_consts] + pub const INFINITY: Self = 1.0 / 0.0; /// Negative infinity (−∞). - #[unstable(feature = "f16", issue = "116909")] - pub const NEG_INFINITY: f16 = -1.0_f16 / 0.0_f16; + #[$assoc_int_consts] + pub const NEG_INFINITY: Self = -1.0 / 0.0; - /// Maximum integer that can be represented exactly in an [`f16`] value, - /// with no other integer converting to the same floating point value. + /// Maximum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i16`] and [`f16`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to - /// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// - /// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` - /// #![feature(f16)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// # #[cfg(target_has_reliable_f16)] { - /// let max_exact_int = f16::MAX_EXACT_INTEGER; - /// assert_eq!(max_exact_int, max_exact_int as f16 as i16); - /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f16 as i16); - /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f16 as i16); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Beyond `f16::MAX_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((max_exact_int + 1) as f16, (max_exact_int + 2) as f16); - /// # }} + #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` - // #[unstable(feature = "f16", issue = "116909")] #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: i16 = (1 << Self::MANTISSA_DIGITS) - 1; + pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - /// Minimum integer that can be represented exactly in an [`f16`] value, - /// with no other integer converting to the same floating point value. + /// Minimum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i16`] and [`f16`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to - /// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// /// This constant is equivalent to `-MAX_EXACT_INTEGER`. /// - /// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` - /// #![feature(f16)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// # #[cfg(target_has_reliable_f16)] { - /// let min_exact_int = f16::MIN_EXACT_INTEGER; - /// assert_eq!(min_exact_int, min_exact_int as f16 as i16); - /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f16 as i16); - /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f16 as i16); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Below `f16::MIN_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((min_exact_int - 1) as f16, (min_exact_int - 2) as f16); - /// # }} + #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` - // #[unstable(feature = "f16", issue = "116909")] #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER; + pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - /// The mask of the bit used to encode the sign of an [`f16`]. + /// The mask of the bit used to encode the sign of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// This bit is set when the sign is negative and unset when the sign is /// positive. /// If you only need to check whether a value is positive or negative, /// [`is_sign_positive`] or [`is_sign_negative`] can be used. /// - /// [`is_sign_positive`]: f16::is_sign_positive - /// [`is_sign_negative`]: f16::is_sign_negative - /// ```rust + /// [`is_sign_positive`]: Self::is_sign_positive + /// [`is_sign_negative`]: Self::is_sign_negative + /// ``` /// #![feature(float_masks)] - /// #![feature(f16)] - /// # #[cfg(target_has_reliable_f16)] { - /// let sign_mask = f16::SIGN_MASK; - /// let a = 1.6552f16; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let a_bits = a.to_bits(); /// /// assert_eq!(a_bits & sign_mask, 0x0); - /// assert_eq!(f16::from_bits(a_bits ^ sign_mask), -a); - /// assert_eq!(sign_mask, (-0.0f16).to_bits()); - /// # } + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] + #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: u16 = 0x8000; + pub const SIGN_MASK: $BitsT = $SIGN_MASK; - /// The mask of the bits used to encode the exponent of an [`f16`]. + /// The mask of the bits used to encode the exponent of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// - /// Note that the exponent is stored as a biased value, with a bias of 15 for `f16`. + /// Note that the exponent is stored as a biased value, with a bias of + #[doc = stringify!($exponent_bias)] + /// for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// - /// ```rust + /// ``` /// #![feature(float_masks)] - /// #![feature(f16)] - /// # #[cfg(target_has_reliable_f16)] { - /// let exponent_mask = f16::EXPONENT_MASK; - /// - /// fn get_exp(a: f16) -> i16 { - /// let bias = 15; - /// let biased = a.to_bits() & f16::EXPONENT_MASK; - /// (biased >> (f16::MANTISSA_DIGITS - 1)).cast_signed() - bias + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] + #[doc = concat!(" let bias = ", $exponent_bias, ";")] + #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] + #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] /// } /// /// assert_eq!(get_exp(0.5), -1); /// assert_eq!(get_exp(1.0), 0); /// assert_eq!(get_exp(2.0), 1); /// assert_eq!(get_exp(4.0), 2); - /// # } + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: u16 = 0x7c00; + pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - /// The mask of the bits used to encode the mantissa of an [`f16`]. + /// The mask of the bits used to encode the mantissa of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// ```rust /// #![feature(float_masks)] - /// #![feature(f16)] - /// # #[cfg(target_has_reliable_f16)] { - /// let mantissa_mask = f16::MANTISSA_MASK; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] /// - /// assert_eq!(0f16.to_bits() & mantissa_mask, 0x0); - /// assert_eq!(1f16.to_bits() & mantissa_mask, 0x0); + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] /// /// // multiplying a finite value by a power of 2 doesn't change its mantissa /// // unless the result or initial value is not normal. - /// let a = 1.6552f16; + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let b = 4.0 * a; /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); /// /// // The maximum and minimum values have a saturated significand - /// assert_eq!(f16::MAX.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK); - /// assert_eq!(f16::MIN.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK); - /// # } + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: u16 = 0x03ff; + pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; /// Minimum representable positive value (min subnormal) - const TINY_BITS: u16 = 0x1; + const TINY_BITS: $BitsT = 0x1; /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: u16 = Self::TINY_BITS | Self::SIGN_MASK; + const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; +} + +#[doc(test(attr( + feature(cfg_target_has_reliable_f16_f128), + allow(internal_features, unused_features) +)))] +impl f16 { + float_impl! { + Self = f16, + Bits = u16, + SignedBits = i16, + BITS = 16, + MANTISSA_DIGITS = 11, + DIGITS = 3, + EPSILON = 9.7656e-4_f16, + MIN = -6.5504e+4_f16, + MIN_POSITIVE = 6.1035e-5_f16, + MAX = 6.5504e+4_f16, + MIN_EXP = -13, + MAX_EXP = 16, + MIN_10_EXP = -4, + MAX_10_EXP = 4, + SIGN_MASK = 0x8000, + EXPONENT_MASK = 0x7c00, + MANTISSA_MASK = 0x03ff, + exponent_bias = 15, + assoc_int_consts = #[unstable(feature = "f16", issue = "116909")], + feature = f16, + has_reliable_cfg = target_has_reliable_f16, + has_reliable_math_cfg = target_has_reliable_f16_math, + } /// Returns `true` if this value is NaN. /// diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index d3dea38dc2fcf..8f25891c8b8a2 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -401,69 +401,107 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[doc(test(attr(allow(unused_features))))] -impl f32 { - /// The radix or base of the internal representation of `f32`. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] +#[rustc_macro_transparency = "semiopaque"] +pub(crate) macro float_impl( + Self = $SelfT:ty, + Bits = $BitsT:ty, + SignedBits = $SignedBitsT:ty, + // Constants + BITS = $BITS:literal, + MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, + DIGITS = $DIGITS:literal, + EPSILON = $EPSILON:literal, + MIN = $MIN:literal, + MIN_POSITIVE = $MIN_POSITIVE:literal, + MAX = $MAX:literal, + MIN_EXP = $MIN_EXP:literal, + MAX_EXP = $MAX_EXP:literal, + MIN_10_EXP = $MIN_10_EXP:literal, + MAX_10_EXP = $MAX_10_EXP:literal, + SIGN_MASK = $SIGN_MASK:literal, + EXPONENT_MASK = $EXPONENT_MASK:literal, + MANTISSA_MASK = $MANTISSA_MASK:literal, + // Values for docs + exponent_bias = $exponent_bias:literal, + // Feature gates + assoc_int_consts = #[$assoc_int_consts:meta], + // Things needed for `f16`/`f128` doctests + $(feature = $feature:ident,)? + $(has_reliable_cfg = $has_reliable_cfg:ident,)? + $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? +) { + + /// The radix or base of the internal representation of + #[doc = concat!("`", stringify!($SelfT), "`.")] + #[$assoc_int_consts] pub const RADIX: u32 = 2; /// The size of this float type in bits. #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = 32; + pub const BITS: u32 = $BITS; /// Number of significant digits in base 2. /// /// Note that the size of the mantissa in the bitwise representation is one /// smaller than this since the leading 1 is not stored explicitly. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MANTISSA_DIGITS: u32 = 24; + #[$assoc_int_consts] + pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; /// Approximate number of significant digits in base 10. /// /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to `f32` and back without loss. + /// significant digits can be converted to + #[doc = concat!("`", stringify!($SelfT), "`")] + /// and back without loss. /// /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). /// - /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const DIGITS: u32 = 6; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + pub const DIGITS: u32 = $DIGITS; - /// [Machine epsilon] value for `f32`. + /// [Machine epsilon] value for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// /// This is the difference between `1.0` and the next larger representable number. /// /// Equal to 21 − [`MANTISSA_DIGITS`]. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - #[rustc_diagnostic_item = "f32_epsilon"] - pub const EPSILON: f32 = 1.1920929e-07_f32; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] + pub const EPSILON: Self = $EPSILON; - /// Smallest finite `f32` value. + /// Smallest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to −[`MAX`]. /// - /// [`MAX`]: f32::MAX - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: f32 = -3.4028235e+38_f32; - /// Smallest positive normal `f32` value. + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MIN: Self = $MIN; + /// Smallest positive normal + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to 2[`MIN_EXP`] − 1. /// - /// [`MIN_EXP`]: f32::MIN_EXP - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_POSITIVE: f32 = 1.1754944e-38_f32; - /// Largest finite `f32` value. + /// [`MIN_EXP`]: Self::MIN_EXP + #[$assoc_int_consts] + pub const MIN_POSITIVE: Self = $MIN_POSITIVE; + /// Largest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. /// - /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS - /// [`MAX_EXP`]: f32::MAX_EXP - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: f32 = 3.4028235e+38_f32; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + /// [`MAX_EXP`]: Self::MAX_EXP + #[$assoc_int_consts] + pub const MAX: Self = $MAX; /// One greater than the minimum possible *normal* power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). @@ -472,8 +510,8 @@ impl f32 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all normal numbers representable by this type are /// greater than or equal to 0.5 × 2MIN_EXP. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_EXP: i32 = -125; + #[$assoc_int_consts] + pub const MIN_EXP: i32 = $MIN_EXP; /// One greater than the maximum possible power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// @@ -481,23 +519,23 @@ impl f32 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all numbers representable by this type are /// strictly less than 2MAX_EXP. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX_EXP: i32 = 128; + #[$assoc_int_consts] + pub const MAX_EXP: i32 = $MAX_EXP; /// Minimum x for which 10x is normal. /// /// Equal to ceil(log10 [`MIN_POSITIVE`]). /// - /// [`MIN_POSITIVE`]: f32::MIN_POSITIVE - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_10_EXP: i32 = -37; + /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE + #[$assoc_int_consts] + pub const MIN_10_EXP: i32 = $MIN_10_EXP; /// Maximum x for which 10x is normal. /// /// Equal to floor(log10 [`MAX`]). /// - /// [`MAX`]: f32::MAX - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX_10_EXP: i32 = 38; + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MAX_10_EXP: i32 = $MAX_10_EXP; /// Not a Number (NaN). /// @@ -511,144 +549,210 @@ impl f32 { /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. /// The concrete bit pattern may change across Rust versions and target platforms. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - #[rustc_diagnostic_item = "f32_nan"] + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] - pub const NAN: f32 = 0.0_f32 / 0.0_f32; + pub const NAN: Self = 0.0 / 0.0; /// Infinity (∞). - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const INFINITY: f32 = 1.0_f32 / 0.0_f32; + #[$assoc_int_consts] + pub const INFINITY: Self = 1.0 / 0.0; /// Negative infinity (−∞). - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32; + #[$assoc_int_consts] + pub const NEG_INFINITY: Self = -1.0 / 0.0; - /// Maximum integer that can be represented exactly in an [`f32`] value, - /// with no other integer converting to the same floating point value. + /// Maximum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i32`] and [`f32`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to - /// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// - /// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// let max_exact_int = f32::MAX_EXACT_INTEGER; - /// assert_eq!(max_exact_int, max_exact_int as f32 as i32); - /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f32 as i32); - /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f32 as i32); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Beyond `f32::MAX_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((max_exact_int + 1) as f32, (max_exact_int + 2) as f32); - /// # } + #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: i32 = (1 << Self::MANTISSA_DIGITS) - 1; + pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - /// Minimum integer that can be represented exactly in an [`f32`] value, - /// with no other integer converting to the same floating point value. + /// Minimum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i32`] and [`f32`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to - /// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// /// This constant is equivalent to `-MAX_EXACT_INTEGER`. /// - /// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// let min_exact_int = f32::MIN_EXACT_INTEGER; - /// assert_eq!(min_exact_int, min_exact_int as f32 as i32); - /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f32 as i32); - /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f32 as i32); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Below `f32::MIN_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((min_exact_int - 1) as f32, (min_exact_int - 2) as f32); - /// # } + #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER; + pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - /// The mask of the bit used to encode the sign of an [`f32`]. + /// The mask of the bit used to encode the sign of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// This bit is set when the sign is negative and unset when the sign is /// positive. /// If you only need to check whether a value is positive or negative, /// [`is_sign_positive`] or [`is_sign_negative`] can be used. /// - /// [`is_sign_positive`]: f32::is_sign_positive - /// [`is_sign_negative`]: f32::is_sign_negative - /// ```rust + /// [`is_sign_positive`]: Self::is_sign_positive + /// [`is_sign_negative`]: Self::is_sign_negative + /// ``` /// #![feature(float_masks)] - /// let sign_mask = f32::SIGN_MASK; - /// let a = 1.6552f32; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let a_bits = a.to_bits(); /// /// assert_eq!(a_bits & sign_mask, 0x0); - /// assert_eq!(f32::from_bits(a_bits ^ sign_mask), -a); - /// assert_eq!(sign_mask, (-0.0f32).to_bits()); + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] + #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: u32 = 0x8000_0000; + pub const SIGN_MASK: $BitsT = $SIGN_MASK; - /// The mask of the bits used to encode the exponent of an [`f32`]. + /// The mask of the bits used to encode the exponent of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// - /// Note that the exponent is stored as a biased value, with a bias of 127 for `f32`. + /// Note that the exponent is stored as a biased value, with a bias of + #[doc = stringify!($exponent_bias)] + /// for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// - /// ```rust + /// ``` /// #![feature(float_masks)] - /// fn get_exp(a: f32) -> i32 { - /// let bias = 127; - /// let biased = a.to_bits() & f32::EXPONENT_MASK; - /// (biased >> (f32::MANTISSA_DIGITS - 1)).cast_signed() - bias + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] + #[doc = concat!(" let bias = ", $exponent_bias, ";")] + #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] + #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] /// } /// /// assert_eq!(get_exp(0.5), -1); /// assert_eq!(get_exp(1.0), 0); /// assert_eq!(get_exp(2.0), 1); /// assert_eq!(get_exp(4.0), 2); + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: u32 = 0x7f80_0000; + pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - /// The mask of the bits used to encode the mantissa of an [`f32`]. + /// The mask of the bits used to encode the mantissa of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// ```rust /// #![feature(float_masks)] - /// let mantissa_mask = f32::MANTISSA_MASK; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] /// - /// assert_eq!(0f32.to_bits() & mantissa_mask, 0x0); - /// assert_eq!(1f32.to_bits() & mantissa_mask, 0x0); + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] /// /// // multiplying a finite value by a power of 2 doesn't change its mantissa /// // unless the result or initial value is not normal. - /// let a = 1.6552f32; + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let b = 4.0 * a; /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); /// /// // The maximum and minimum values have a saturated significand - /// assert_eq!(f32::MAX.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK); - /// assert_eq!(f32::MIN.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK); + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: u32 = 0x007f_ffff; + pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; /// Minimum representable positive value (min subnormal) - const TINY_BITS: u32 = 0x1; + const TINY_BITS: $BitsT = 0x1; /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: u32 = Self::TINY_BITS | Self::SIGN_MASK; + const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; +} + +#[doc(test(attr(allow(unused_features))))] +impl f32 { + float_impl! { + Self = f32, + Bits = u32, + SignedBits = i32, + BITS = 32, + MANTISSA_DIGITS = 24, + DIGITS = 6, + EPSILON = 1.1920929e-07_f32, + MIN = -3.4028235e+38_f32, + MIN_POSITIVE = 1.1754944e-38_f32, + MAX = 3.4028235e+38_f32, + MIN_EXP = -125, + MAX_EXP = 128, + MIN_10_EXP = -37, + MAX_10_EXP = 38, + SIGN_MASK = 0x8000_0000, + EXPONENT_MASK = 0x7f80_0000, + MANTISSA_MASK = 0x007f_ffff, + exponent_bias = 127, + assoc_int_consts = #[stable(feature = "assoc_int_consts", since = "1.43.0")], + } /// Returns `true` if this value is NaN. /// diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7c5082749cd11..411afd965b717 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -401,68 +401,107 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[doc(test(attr(allow(unused_features))))] -impl f64 { - /// The radix or base of the internal representation of `f64`. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] +#[rustc_macro_transparency = "semiopaque"] +pub(crate) macro float_impl( + Self = $SelfT:ty, + Bits = $BitsT:ty, + SignedBits = $SignedBitsT:ty, + // Constants + BITS = $BITS:literal, + MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, + DIGITS = $DIGITS:literal, + EPSILON = $EPSILON:literal, + MIN = $MIN:literal, + MIN_POSITIVE = $MIN_POSITIVE:literal, + MAX = $MAX:literal, + MIN_EXP = $MIN_EXP:literal, + MAX_EXP = $MAX_EXP:literal, + MIN_10_EXP = $MIN_10_EXP:literal, + MAX_10_EXP = $MAX_10_EXP:literal, + SIGN_MASK = $SIGN_MASK:literal, + EXPONENT_MASK = $EXPONENT_MASK:literal, + MANTISSA_MASK = $MANTISSA_MASK:literal, + // Values for docs + exponent_bias = $exponent_bias:literal, + // Feature gates + assoc_int_consts = #[$assoc_int_consts:meta], + // Things needed for `f16`/`f128` doctests + $(feature = $feature:ident,)? + $(has_reliable_cfg = $has_reliable_cfg:ident,)? + $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? +) { + + /// The radix or base of the internal representation of + #[doc = concat!("`", stringify!($SelfT), "`.")] + #[$assoc_int_consts] pub const RADIX: u32 = 2; /// The size of this float type in bits. #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = 64; + pub const BITS: u32 = $BITS; /// Number of significant digits in base 2. /// /// Note that the size of the mantissa in the bitwise representation is one /// smaller than this since the leading 1 is not stored explicitly. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MANTISSA_DIGITS: u32 = 53; + #[$assoc_int_consts] + pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; + /// Approximate number of significant digits in base 10. /// /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to `f64` and back without loss. + /// significant digits can be converted to + #[doc = concat!("`", stringify!($SelfT), "`")] + /// and back without loss. /// /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). /// - /// [`MANTISSA_DIGITS`]: f64::MANTISSA_DIGITS - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const DIGITS: u32 = 15; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + pub const DIGITS: u32 = $DIGITS; - /// [Machine epsilon] value for `f64`. + /// [Machine epsilon] value for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// /// This is the difference between `1.0` and the next larger representable number. /// /// Equal to 21 − [`MANTISSA_DIGITS`]. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: f64::MANTISSA_DIGITS - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - #[rustc_diagnostic_item = "f64_epsilon"] - pub const EPSILON: f64 = 2.220446049250313e-16_f64; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] + pub const EPSILON: Self = $EPSILON; - /// Smallest finite `f64` value. + /// Smallest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to −[`MAX`]. /// - /// [`MAX`]: f64::MAX - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: f64 = -1.7976931348623157e+308_f64; - /// Smallest positive normal `f64` value. + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MIN: Self = $MIN; + /// Smallest positive normal + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to 2[`MIN_EXP`] − 1. /// - /// [`MIN_EXP`]: f64::MIN_EXP - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_POSITIVE: f64 = 2.2250738585072014e-308_f64; - /// Largest finite `f64` value. + /// [`MIN_EXP`]: Self::MIN_EXP + #[$assoc_int_consts] + pub const MIN_POSITIVE: Self = $MIN_POSITIVE; + /// Largest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. /// /// Equal to /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. /// - /// [`MANTISSA_DIGITS`]: f64::MANTISSA_DIGITS - /// [`MAX_EXP`]: f64::MAX_EXP - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: f64 = 1.7976931348623157e+308_f64; + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + /// [`MAX_EXP`]: Self::MAX_EXP + #[$assoc_int_consts] + pub const MAX: Self = $MAX; /// One greater than the minimum possible *normal* power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). @@ -471,8 +510,8 @@ impl f64 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all normal numbers representable by this type are /// greater than or equal to 0.5 × 2MIN_EXP. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_EXP: i32 = -1021; + #[$assoc_int_consts] + pub const MIN_EXP: i32 = $MIN_EXP; /// One greater than the maximum possible power of 2 exponent /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). /// @@ -480,23 +519,23 @@ impl f64 { /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). /// In other words, all numbers representable by this type are /// strictly less than 2MAX_EXP. - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX_EXP: i32 = 1024; + #[$assoc_int_consts] + pub const MAX_EXP: i32 = $MAX_EXP; /// Minimum x for which 10x is normal. /// /// Equal to ceil(log10 [`MIN_POSITIVE`]). /// - /// [`MIN_POSITIVE`]: f64::MIN_POSITIVE - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN_10_EXP: i32 = -307; + /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE + #[$assoc_int_consts] + pub const MIN_10_EXP: i32 = $MIN_10_EXP; /// Maximum x for which 10x is normal. /// /// Equal to floor(log10 [`MAX`]). /// - /// [`MAX`]: f64::MAX - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX_10_EXP: i32 = 308; + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MAX_10_EXP: i32 = $MAX_10_EXP; /// Not a Number (NaN). /// @@ -510,144 +549,210 @@ impl f64 { /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. /// The concrete bit pattern may change across Rust versions and target platforms. - #[rustc_diagnostic_item = "f64_nan"] - #[stable(feature = "assoc_int_consts", since = "1.43.0")] + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] - pub const NAN: f64 = 0.0_f64 / 0.0_f64; + pub const NAN: Self = 0.0 / 0.0; /// Infinity (∞). - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const INFINITY: f64 = 1.0_f64 / 0.0_f64; + #[$assoc_int_consts] + pub const INFINITY: Self = 1.0 / 0.0; /// Negative infinity (−∞). - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64; + #[$assoc_int_consts] + pub const NEG_INFINITY: Self = -1.0 / 0.0; - /// Maximum integer that can be represented exactly in an [`f64`] value, - /// with no other integer converting to the same floating point value. + /// Maximum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i64`] and [`f64`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to - /// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// - /// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// let max_exact_int = f64::MAX_EXACT_INTEGER; - /// assert_eq!(max_exact_int, max_exact_int as f64 as i64); - /// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f64 as i64); - /// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f64 as i64); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Beyond `f64::MAX_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((max_exact_int + 1) as f64, (max_exact_int + 2) as f64); - /// # } + #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: i64 = (1 << Self::MANTISSA_DIGITS) - 1; + pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - /// Minimum integer that can be represented exactly in an [`f64`] value, - /// with no other integer converting to the same floating point value. + /// Minimum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. /// /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between [`i64`] and [`f64`] values. - /// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to - /// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value - /// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a /// "one-to-one" mapping. /// /// This constant is equivalent to `-MAX_EXACT_INTEGER`. /// - /// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER /// ``` + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? /// #![feature(float_exact_integer_constants)] /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - /// let min_exact_int = f64::MIN_EXACT_INTEGER; - /// assert_eq!(min_exact_int, min_exact_int as f64 as i64); - /// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f64 as i64); - /// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f64 as i64); + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] /// - /// // Below `f64::MIN_EXACT_INTEGER`, multiple integers can map to one float value - /// assert_eq!((min_exact_int - 1) as f64, (min_exact_int - 2) as f64); - /// # } + #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] /// ``` #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER; + pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - /// The mask of the bit used to encode the sign of an [`f64`]. + /// The mask of the bit used to encode the sign of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// This bit is set when the sign is negative and unset when the sign is /// positive. /// If you only need to check whether a value is positive or negative, /// [`is_sign_positive`] or [`is_sign_negative`] can be used. /// - /// [`is_sign_positive`]: f64::is_sign_positive - /// [`is_sign_negative`]: f64::is_sign_negative - /// ```rust + /// [`is_sign_positive`]: Self::is_sign_positive + /// [`is_sign_negative`]: Self::is_sign_negative + /// ``` /// #![feature(float_masks)] - /// let sign_mask = f64::SIGN_MASK; - /// let a = 1.6552f64; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let a_bits = a.to_bits(); /// /// assert_eq!(a_bits & sign_mask, 0x0); - /// assert_eq!(f64::from_bits(a_bits ^ sign_mask), -a); - /// assert_eq!(sign_mask, (-0.0f64).to_bits()); + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] + #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: u64 = 0x8000_0000_0000_0000; + pub const SIGN_MASK: $BitsT = $SIGN_MASK; - /// The mask of the bits used to encode the exponent of an [`f64`]. + /// The mask of the bits used to encode the exponent of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// - /// Note that the exponent is stored as a biased value, with a bias of 1024 for `f64`. + /// Note that the exponent is stored as a biased value, with a bias of + #[doc = stringify!($exponent_bias)] + /// for + #[doc = concat!("`", stringify!($SelfT), "`.")] /// - /// ```rust + /// ``` /// #![feature(float_masks)] - /// fn get_exp(a: f64) -> i64 { - /// let bias = 1023; - /// let biased = a.to_bits() & f64::EXPONENT_MASK; - /// (biased >> (f64::MANTISSA_DIGITS - 1)).cast_signed() - bias + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] + #[doc = concat!(" let bias = ", $exponent_bias, ";")] + #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] + #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] /// } /// /// assert_eq!(get_exp(0.5), -1); /// assert_eq!(get_exp(1.0), 0); /// assert_eq!(get_exp(2.0), 1); /// assert_eq!(get_exp(4.0), 2); + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000; + pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - /// The mask of the bits used to encode the mantissa of an [`f64`]. + /// The mask of the bits used to encode the mantissa of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] /// /// ```rust /// #![feature(float_masks)] - /// let mantissa_mask = f64::MANTISSA_MASK; + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] /// - /// assert_eq!(0f64.to_bits() & mantissa_mask, 0x0); - /// assert_eq!(1f64.to_bits() & mantissa_mask, 0x0); + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] /// /// // multiplying a finite value by a power of 2 doesn't change its mantissa /// // unless the result or initial value is not normal. - /// let a = 1.6552f64; + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] /// let b = 4.0 * a; /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); /// /// // The maximum and minimum values have a saturated significand - /// assert_eq!(f64::MAX.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK); - /// assert_eq!(f64::MIN.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK); + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + $(${ignore($has_reliable_cfg)} + /// # } + )? /// ``` #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: u64 = 0x000f_ffff_ffff_ffff; + pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; /// Minimum representable positive value (min subnormal) - const TINY_BITS: u64 = 0x1; + const TINY_BITS: $BitsT = 0x1; /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: u64 = Self::TINY_BITS | Self::SIGN_MASK; + const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; +} + +#[doc(test(attr(allow(unused_features))))] +impl f64 { + float_impl! { + Self = f64, + Bits = u64, + SignedBits = i64, + BITS = 64, + MANTISSA_DIGITS = 53, + DIGITS = 15, + EPSILON = 2.220446049250313e-16_f64, + MIN = -1.7976931348623157e+308_f64, + MIN_POSITIVE = 2.2250738585072014e-308_f64, + MAX = 1.7976931348623157e+308_f64, + MIN_EXP = -1021, + MAX_EXP = 1024, + MIN_10_EXP = -307, + MAX_10_EXP = 308, + SIGN_MASK = 0x8000_0000_0000_0000, + EXPONENT_MASK = 0x7ff0_0000_0000_0000, + MANTISSA_MASK = 0x000f_ffff_ffff_ffff, + exponent_bias = 1023, + assoc_int_consts = #[stable(feature = "assoc_int_consts", since = "1.43.0")], + } /// Returns `true` if this value is NaN. /// diff --git a/library/core/src/num/float_macros.rs b/library/core/src/num/float_macros.rs new file mode 100644 index 0000000000000..36580a17e7c5e --- /dev/null +++ b/library/core/src/num/float_macros.rs @@ -0,0 +1,329 @@ +#[expect(unused_macros)] +#[rustc_macro_transparency = "semiopaque"] +pub(crate) macro float_impl( + Self = $SelfT:ty, + Bits = $BitsT:ty, + SignedBits = $SignedBitsT:ty, + // Constants + BITS = $BITS:literal, + MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, + DIGITS = $DIGITS:literal, + EPSILON = $EPSILON:literal, + MIN = $MIN:literal, + MIN_POSITIVE = $MIN_POSITIVE:literal, + MAX = $MAX:literal, + MIN_EXP = $MIN_EXP:literal, + MAX_EXP = $MAX_EXP:literal, + MIN_10_EXP = $MIN_10_EXP:literal, + MAX_10_EXP = $MAX_10_EXP:literal, + SIGN_MASK = $SIGN_MASK:literal, + EXPONENT_MASK = $EXPONENT_MASK:literal, + MANTISSA_MASK = $MANTISSA_MASK:literal, + // Values for docs + exponent_bias = $exponent_bias:literal, + // Feature gates + assoc_int_consts = #[$assoc_int_consts:meta], + // Things needed for `f16`/`f128` doctests + $(feature = $feature:ident,)? + $(has_reliable_cfg = $has_reliable_cfg:ident,)? + $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? +) { + + /// The radix or base of the internal representation of + #[doc = concat!("`", stringify!($SelfT), "`.")] + #[$assoc_int_consts] + pub const RADIX: u32 = 2; + + /// The size of this float type in bits. + #[unstable(feature = "float_bits_const", issue = "151073")] + pub const BITS: u32 = $BITS; + + /// Number of significant digits in base 2. + /// + /// Note that the size of the mantissa in the bitwise representation is one + /// smaller than this since the leading 1 is not stored explicitly. + #[$assoc_int_consts] + pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; + + /// Approximate number of significant digits in base 10. + /// + /// This is the maximum x such that any decimal number with x + /// significant digits can be converted to + #[doc = concat!("`", stringify!($SelfT), "`")] + /// and back without loss. + /// + /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). + /// + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + pub const DIGITS: u32 = $DIGITS; + + /// [Machine epsilon] value for + #[doc = concat!("`", stringify!($SelfT), "`.")] + /// + /// This is the difference between `1.0` and the next larger representable number. + /// + /// Equal to 21 − [`MANTISSA_DIGITS`]. + /// + /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] + pub const EPSILON: Self = $EPSILON; + + /// Smallest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. + /// + /// Equal to −[`MAX`]. + /// + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MIN: Self = $MIN; + /// Smallest positive normal + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. + /// + /// Equal to 2[`MIN_EXP`] − 1. + /// + /// [`MIN_EXP`]: Self::MIN_EXP + #[$assoc_int_consts] + pub const MIN_POSITIVE: Self = $MIN_POSITIVE; + /// Largest finite + #[doc = concat!("`", stringify!($SelfT), "`")] + /// value. + /// + /// Equal to + /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. + /// + /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS + /// [`MAX_EXP`]: Self::MAX_EXP + #[$assoc_int_consts] + pub const MAX: Self = $MAX; + + /// One greater than the minimum possible *normal* power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). + /// + /// This corresponds to the exact minimum possible *normal* power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all normal numbers representable by this type are + /// greater than or equal to 0.5 × 2MIN_EXP. + #[$assoc_int_consts] + pub const MIN_EXP: i32 = $MIN_EXP; + /// One greater than the maximum possible power of 2 exponent + /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). + /// + /// This corresponds to the exact maximum possible power of 2 exponent + /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). + /// In other words, all numbers representable by this type are + /// strictly less than 2MAX_EXP. + #[$assoc_int_consts] + pub const MAX_EXP: i32 = $MAX_EXP; + + /// Minimum x for which 10x is normal. + /// + /// Equal to ceil(log10 [`MIN_POSITIVE`]). + /// + /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE + #[$assoc_int_consts] + pub const MIN_10_EXP: i32 = $MIN_10_EXP; + /// Maximum x for which 10x is normal. + /// + /// Equal to floor(log10 [`MAX`]). + /// + /// [`MAX`]: Self::MAX + #[$assoc_int_consts] + pub const MAX_10_EXP: i32 = $MAX_10_EXP; + + /// Not a Number (NaN). + /// + /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are + /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and + /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) + /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more + /// info. + /// + /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions + /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is + /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. + /// The concrete bit pattern may change across Rust versions and target platforms. + #[$assoc_int_consts] + #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] + #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] + pub const NAN: Self = 0.0 / 0.0; + /// Infinity (∞). + #[$assoc_int_consts] + pub const INFINITY: Self = 1.0 / 0.0; + /// Negative infinity (−∞). + #[$assoc_int_consts] + pub const NEG_INFINITY: Self = -1.0 / 0.0; + + /// Maximum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER + /// ``` + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + /// #![feature(float_exact_integer_constants)] + /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 + /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + /// + #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] + /// ``` + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; + + /// Minimum integer that can be represented exactly in an + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value, with no other integer converting to the same floating point value. + /// + /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, + /// there is a "one-to-one" mapping between + #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] + /// and + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// and back to + #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] + /// but `MAX_EXACT_INTEGER + 2` converts to the same + #[doc = concat!("[`", stringify!($SelfT), "`]")] + /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a + /// "one-to-one" mapping. + /// + /// This constant is equivalent to `-MAX_EXACT_INTEGER`. + /// + /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER + /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER + /// ``` + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + /// #![feature(float_exact_integer_constants)] + /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 + /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] + #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] + /// + #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] + #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] + #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] + /// ``` + #[unstable(feature = "float_exact_integer_constants", issue = "152466")] + pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; + + /// The mask of the bit used to encode the sign of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] + /// + /// This bit is set when the sign is negative and unset when the sign is + /// positive. + /// If you only need to check whether a value is positive or negative, + /// [`is_sign_positive`] or [`is_sign_negative`] can be used. + /// + /// [`is_sign_positive`]: Self::is_sign_positive + /// [`is_sign_negative`]: Self::is_sign_negative + /// ``` + /// #![feature(float_masks)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] + /// let a_bits = a.to_bits(); + /// + /// assert_eq!(a_bits & sign_mask, 0x0); + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] + #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] + $(${ignore($has_reliable_cfg)} + /// # } + )? + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const SIGN_MASK: $BitsT = $SIGN_MASK; + + /// The mask of the bits used to encode the exponent of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] + /// + /// Note that the exponent is stored as a biased value, with a bias of + #[doc = stringify!($exponent_bias)] + /// for + #[doc = concat!("`", stringify!($SelfT), "`.")] + /// + /// ``` + /// #![feature(float_masks)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] + #[doc = concat!(" let bias = ", $exponent_bias, ";")] + #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] + #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] + /// } + /// + /// assert_eq!(get_exp(0.5), -1); + /// assert_eq!(get_exp(1.0), 0); + /// assert_eq!(get_exp(2.0), 1); + /// assert_eq!(get_exp(4.0), 2); + $(${ignore($has_reliable_cfg)} + /// # } + )? + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; + + /// The mask of the bits used to encode the mantissa of an + #[doc = concat!("[`", stringify!($SelfT), "`].")] + /// + /// ```rust + /// #![feature(float_masks)] + $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? + $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? + #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] + /// + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] + /// + /// // multiplying a finite value by a power of 2 doesn't change its mantissa + /// // unless the result or initial value is not normal. + #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] + /// let b = 4.0 * a; + /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); + /// + /// // The maximum and minimum values have a saturated significand + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] + $(${ignore($has_reliable_cfg)} + /// # } + )? + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; + + /// Minimum representable positive value (min subnormal) + const TINY_BITS: $BitsT = 0x1; + + /// Minimum representable negative value (min negative subnormal) + const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 25326f4f066c6..cdfd5d60212dc 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -46,6 +46,7 @@ mod uint_macros; // import uint_impl! mod bfloat; mod complex; mod error; +pub(crate) mod float_macros; #[cfg(not(no_fp_fmt_parse))] mod float_parse; mod nonzero; From 6af8cac30740f874ade3c898e7b3c011c6e59f89 Mon Sep 17 00:00:00 2001 From: Bee Date: Mon, 28 Sep 2026 02:12:46 +0100 Subject: [PATCH 02/29] Remove duplicate `float_impl` macros --- library/core/src/num/f128.rs | 330 +-------------------------- library/core/src/num/f16.rs | 330 +-------------------------- library/core/src/num/f32.rs | 330 +-------------------------- library/core/src/num/f64.rs | 330 +-------------------------- library/core/src/num/float_macros.rs | 1 - 5 files changed, 4 insertions(+), 1317 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 8f8a6af0aaccd..2c26876b88d8b 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -14,6 +14,7 @@ use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; +use crate::num::float_macros::float_impl; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -150,335 +151,6 @@ pub mod consts { pub const LN_10: f128 = 2.30258509299404568401799145468436420760110148862877297603333_f128; } -#[rustc_macro_transparency = "semiopaque"] -pub(crate) macro float_impl( - Self = $SelfT:ty, - Bits = $BitsT:ty, - SignedBits = $SignedBitsT:ty, - // Constants - BITS = $BITS:literal, - MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, - DIGITS = $DIGITS:literal, - EPSILON = $EPSILON:literal, - MIN = $MIN:literal, - MIN_POSITIVE = $MIN_POSITIVE:literal, - MAX = $MAX:literal, - MIN_EXP = $MIN_EXP:literal, - MAX_EXP = $MAX_EXP:literal, - MIN_10_EXP = $MIN_10_EXP:literal, - MAX_10_EXP = $MAX_10_EXP:literal, - SIGN_MASK = $SIGN_MASK:literal, - EXPONENT_MASK = $EXPONENT_MASK:literal, - MANTISSA_MASK = $MANTISSA_MASK:literal, - // Values for docs - exponent_bias = $exponent_bias:literal, - // Feature gates - assoc_int_consts = #[$assoc_int_consts:meta], - // Things needed for `f16`/`f128` doctests - $(feature = $feature:ident,)? - $(has_reliable_cfg = $has_reliable_cfg:ident,)? - $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? -) { - - /// The radix or base of the internal representation of - #[doc = concat!("`", stringify!($SelfT), "`.")] - #[$assoc_int_consts] - pub const RADIX: u32 = 2; - - /// The size of this float type in bits. - #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = $BITS; - - /// Number of significant digits in base 2. - /// - /// Note that the size of the mantissa in the bitwise representation is one - /// smaller than this since the leading 1 is not stored explicitly. - #[$assoc_int_consts] - pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; - - /// Approximate number of significant digits in base 10. - /// - /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to - #[doc = concat!("`", stringify!($SelfT), "`")] - /// and back without loss. - /// - /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - pub const DIGITS: u32 = $DIGITS; - - /// [Machine epsilon] value for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// This is the difference between `1.0` and the next larger representable number. - /// - /// Equal to 21 − [`MANTISSA_DIGITS`]. - /// - /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] - pub const EPSILON: Self = $EPSILON; - - /// Smallest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to −[`MAX`]. - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MIN: Self = $MIN; - /// Smallest positive normal - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to 2[`MIN_EXP`] − 1. - /// - /// [`MIN_EXP`]: Self::MIN_EXP - #[$assoc_int_consts] - pub const MIN_POSITIVE: Self = $MIN_POSITIVE; - /// Largest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to - /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - /// [`MAX_EXP`]: Self::MAX_EXP - #[$assoc_int_consts] - pub const MAX: Self = $MAX; - - /// One greater than the minimum possible *normal* power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact minimum possible *normal* power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all normal numbers representable by this type are - /// greater than or equal to 0.5 × 2MIN_EXP. - #[$assoc_int_consts] - pub const MIN_EXP: i32 = $MIN_EXP; - /// One greater than the maximum possible power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact maximum possible power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all numbers representable by this type are - /// strictly less than 2MAX_EXP. - #[$assoc_int_consts] - pub const MAX_EXP: i32 = $MAX_EXP; - - /// Minimum x for which 10x is normal. - /// - /// Equal to ceil(log10 [`MIN_POSITIVE`]). - /// - /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE - #[$assoc_int_consts] - pub const MIN_10_EXP: i32 = $MIN_10_EXP; - /// Maximum x for which 10x is normal. - /// - /// Equal to floor(log10 [`MAX`]). - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MAX_10_EXP: i32 = $MAX_10_EXP; - - /// Not a Number (NaN). - /// - /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are - /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and - /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) - /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more - /// info. - /// - /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions - /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is - /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. - /// The concrete bit pattern may change across Rust versions and target platforms. - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] - #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] - pub const NAN: Self = 0.0 / 0.0; - /// Infinity (∞). - #[$assoc_int_consts] - pub const INFINITY: Self = 1.0 / 0.0; - /// Negative infinity (−∞). - #[$assoc_int_consts] - pub const NEG_INFINITY: Self = -1.0 / 0.0; - - /// Maximum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - - /// Minimum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// This constant is equivalent to `-MAX_EXACT_INTEGER`. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - - /// The mask of the bit used to encode the sign of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// This bit is set when the sign is negative and unset when the sign is - /// positive. - /// If you only need to check whether a value is positive or negative, - /// [`is_sign_positive`] or [`is_sign_negative`] can be used. - /// - /// [`is_sign_positive`]: Self::is_sign_positive - /// [`is_sign_negative`]: Self::is_sign_negative - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let a_bits = a.to_bits(); - /// - /// assert_eq!(a_bits & sign_mask, 0x0); - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] - #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: $BitsT = $SIGN_MASK; - - /// The mask of the bits used to encode the exponent of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// Note that the exponent is stored as a biased value, with a bias of - #[doc = stringify!($exponent_bias)] - /// for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] - #[doc = concat!(" let bias = ", $exponent_bias, ";")] - #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] - #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] - /// } - /// - /// assert_eq!(get_exp(0.5), -1); - /// assert_eq!(get_exp(1.0), 0); - /// assert_eq!(get_exp(2.0), 1); - /// assert_eq!(get_exp(4.0), 2); - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - - /// The mask of the bits used to encode the mantissa of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// ```rust - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] - /// - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - /// - /// // multiplying a finite value by a power of 2 doesn't change its mantissa - /// // unless the result or initial value is not normal. - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let b = 4.0 * a; - /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); - /// - /// // The maximum and minimum values have a saturated significand - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; - - /// Minimum representable positive value (min subnormal) - const TINY_BITS: $BitsT = 0x1; - - /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; -} - #[doc(test(attr( feature(cfg_target_has_reliable_f16_f128), allow(internal_features, unused_features) diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 48fe45402aeac..922eb1a523bae 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -14,6 +14,7 @@ use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; +use crate::num::float_macros::float_impl; #[cfg(not(test))] use crate::num::imp::libm; use crate::panic::const_assert; @@ -144,335 +145,6 @@ pub mod consts { pub const LN_10: f16 = 2.30258509299404568401799145468436421_f16; } -#[rustc_macro_transparency = "semiopaque"] -pub(crate) macro float_impl( - Self = $SelfT:ty, - Bits = $BitsT:ty, - SignedBits = $SignedBitsT:ty, - // Constants - BITS = $BITS:literal, - MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, - DIGITS = $DIGITS:literal, - EPSILON = $EPSILON:literal, - MIN = $MIN:literal, - MIN_POSITIVE = $MIN_POSITIVE:literal, - MAX = $MAX:literal, - MIN_EXP = $MIN_EXP:literal, - MAX_EXP = $MAX_EXP:literal, - MIN_10_EXP = $MIN_10_EXP:literal, - MAX_10_EXP = $MAX_10_EXP:literal, - SIGN_MASK = $SIGN_MASK:literal, - EXPONENT_MASK = $EXPONENT_MASK:literal, - MANTISSA_MASK = $MANTISSA_MASK:literal, - // Values for docs - exponent_bias = $exponent_bias:literal, - // Feature gates - assoc_int_consts = #[$assoc_int_consts:meta], - // Things needed for `f16`/`f128` doctests - $(feature = $feature:ident,)? - $(has_reliable_cfg = $has_reliable_cfg:ident,)? - $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? -) { - - /// The radix or base of the internal representation of - #[doc = concat!("`", stringify!($SelfT), "`.")] - #[$assoc_int_consts] - pub const RADIX: u32 = 2; - - /// The size of this float type in bits. - #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = $BITS; - - /// Number of significant digits in base 2. - /// - /// Note that the size of the mantissa in the bitwise representation is one - /// smaller than this since the leading 1 is not stored explicitly. - #[$assoc_int_consts] - pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; - - /// Approximate number of significant digits in base 10. - /// - /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to - #[doc = concat!("`", stringify!($SelfT), "`")] - /// and back without loss. - /// - /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - pub const DIGITS: u32 = $DIGITS; - - /// [Machine epsilon] value for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// This is the difference between `1.0` and the next larger representable number. - /// - /// Equal to 21 − [`MANTISSA_DIGITS`]. - /// - /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] - pub const EPSILON: Self = $EPSILON; - - /// Smallest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to −[`MAX`]. - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MIN: Self = $MIN; - /// Smallest positive normal - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to 2[`MIN_EXP`] − 1. - /// - /// [`MIN_EXP`]: Self::MIN_EXP - #[$assoc_int_consts] - pub const MIN_POSITIVE: Self = $MIN_POSITIVE; - /// Largest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to - /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - /// [`MAX_EXP`]: Self::MAX_EXP - #[$assoc_int_consts] - pub const MAX: Self = $MAX; - - /// One greater than the minimum possible *normal* power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact minimum possible *normal* power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all normal numbers representable by this type are - /// greater than or equal to 0.5 × 2MIN_EXP. - #[$assoc_int_consts] - pub const MIN_EXP: i32 = $MIN_EXP; - /// One greater than the maximum possible power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact maximum possible power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all numbers representable by this type are - /// strictly less than 2MAX_EXP. - #[$assoc_int_consts] - pub const MAX_EXP: i32 = $MAX_EXP; - - /// Minimum x for which 10x is normal. - /// - /// Equal to ceil(log10 [`MIN_POSITIVE`]). - /// - /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE - #[$assoc_int_consts] - pub const MIN_10_EXP: i32 = $MIN_10_EXP; - /// Maximum x for which 10x is normal. - /// - /// Equal to floor(log10 [`MAX`]). - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MAX_10_EXP: i32 = $MAX_10_EXP; - - /// Not a Number (NaN). - /// - /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are - /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and - /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) - /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more - /// info. - /// - /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions - /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is - /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. - /// The concrete bit pattern may change across Rust versions and target platforms. - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] - #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] - pub const NAN: Self = 0.0 / 0.0; - /// Infinity (∞). - #[$assoc_int_consts] - pub const INFINITY: Self = 1.0 / 0.0; - /// Negative infinity (−∞). - #[$assoc_int_consts] - pub const NEG_INFINITY: Self = -1.0 / 0.0; - - /// Maximum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - - /// Minimum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// This constant is equivalent to `-MAX_EXACT_INTEGER`. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - - /// The mask of the bit used to encode the sign of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// This bit is set when the sign is negative and unset when the sign is - /// positive. - /// If you only need to check whether a value is positive or negative, - /// [`is_sign_positive`] or [`is_sign_negative`] can be used. - /// - /// [`is_sign_positive`]: Self::is_sign_positive - /// [`is_sign_negative`]: Self::is_sign_negative - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let a_bits = a.to_bits(); - /// - /// assert_eq!(a_bits & sign_mask, 0x0); - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] - #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: $BitsT = $SIGN_MASK; - - /// The mask of the bits used to encode the exponent of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// Note that the exponent is stored as a biased value, with a bias of - #[doc = stringify!($exponent_bias)] - /// for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] - #[doc = concat!(" let bias = ", $exponent_bias, ";")] - #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] - #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] - /// } - /// - /// assert_eq!(get_exp(0.5), -1); - /// assert_eq!(get_exp(1.0), 0); - /// assert_eq!(get_exp(2.0), 1); - /// assert_eq!(get_exp(4.0), 2); - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - - /// The mask of the bits used to encode the mantissa of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// ```rust - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] - /// - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - /// - /// // multiplying a finite value by a power of 2 doesn't change its mantissa - /// // unless the result or initial value is not normal. - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let b = 4.0 * a; - /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); - /// - /// // The maximum and minimum values have a saturated significand - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; - - /// Minimum representable positive value (min subnormal) - const TINY_BITS: $BitsT = 0x1; - - /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; -} - #[doc(test(attr( feature(cfg_target_has_reliable_f16_f128), allow(internal_features, unused_features) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 8f25891c8b8a2..a36ddadb261c6 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -14,6 +14,7 @@ use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; +use crate::num::float_macros::float_impl; use crate::panic::const_assert; use crate::{cfg_select, intrinsics, mem}; @@ -401,335 +402,6 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[rustc_macro_transparency = "semiopaque"] -pub(crate) macro float_impl( - Self = $SelfT:ty, - Bits = $BitsT:ty, - SignedBits = $SignedBitsT:ty, - // Constants - BITS = $BITS:literal, - MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, - DIGITS = $DIGITS:literal, - EPSILON = $EPSILON:literal, - MIN = $MIN:literal, - MIN_POSITIVE = $MIN_POSITIVE:literal, - MAX = $MAX:literal, - MIN_EXP = $MIN_EXP:literal, - MAX_EXP = $MAX_EXP:literal, - MIN_10_EXP = $MIN_10_EXP:literal, - MAX_10_EXP = $MAX_10_EXP:literal, - SIGN_MASK = $SIGN_MASK:literal, - EXPONENT_MASK = $EXPONENT_MASK:literal, - MANTISSA_MASK = $MANTISSA_MASK:literal, - // Values for docs - exponent_bias = $exponent_bias:literal, - // Feature gates - assoc_int_consts = #[$assoc_int_consts:meta], - // Things needed for `f16`/`f128` doctests - $(feature = $feature:ident,)? - $(has_reliable_cfg = $has_reliable_cfg:ident,)? - $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? -) { - - /// The radix or base of the internal representation of - #[doc = concat!("`", stringify!($SelfT), "`.")] - #[$assoc_int_consts] - pub const RADIX: u32 = 2; - - /// The size of this float type in bits. - #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = $BITS; - - /// Number of significant digits in base 2. - /// - /// Note that the size of the mantissa in the bitwise representation is one - /// smaller than this since the leading 1 is not stored explicitly. - #[$assoc_int_consts] - pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; - - /// Approximate number of significant digits in base 10. - /// - /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to - #[doc = concat!("`", stringify!($SelfT), "`")] - /// and back without loss. - /// - /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - pub const DIGITS: u32 = $DIGITS; - - /// [Machine epsilon] value for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// This is the difference between `1.0` and the next larger representable number. - /// - /// Equal to 21 − [`MANTISSA_DIGITS`]. - /// - /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] - pub const EPSILON: Self = $EPSILON; - - /// Smallest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to −[`MAX`]. - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MIN: Self = $MIN; - /// Smallest positive normal - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to 2[`MIN_EXP`] − 1. - /// - /// [`MIN_EXP`]: Self::MIN_EXP - #[$assoc_int_consts] - pub const MIN_POSITIVE: Self = $MIN_POSITIVE; - /// Largest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to - /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - /// [`MAX_EXP`]: Self::MAX_EXP - #[$assoc_int_consts] - pub const MAX: Self = $MAX; - - /// One greater than the minimum possible *normal* power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact minimum possible *normal* power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all normal numbers representable by this type are - /// greater than or equal to 0.5 × 2MIN_EXP. - #[$assoc_int_consts] - pub const MIN_EXP: i32 = $MIN_EXP; - /// One greater than the maximum possible power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact maximum possible power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all numbers representable by this type are - /// strictly less than 2MAX_EXP. - #[$assoc_int_consts] - pub const MAX_EXP: i32 = $MAX_EXP; - - /// Minimum x for which 10x is normal. - /// - /// Equal to ceil(log10 [`MIN_POSITIVE`]). - /// - /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE - #[$assoc_int_consts] - pub const MIN_10_EXP: i32 = $MIN_10_EXP; - /// Maximum x for which 10x is normal. - /// - /// Equal to floor(log10 [`MAX`]). - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MAX_10_EXP: i32 = $MAX_10_EXP; - - /// Not a Number (NaN). - /// - /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are - /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and - /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) - /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more - /// info. - /// - /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions - /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is - /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. - /// The concrete bit pattern may change across Rust versions and target platforms. - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] - #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] - pub const NAN: Self = 0.0 / 0.0; - /// Infinity (∞). - #[$assoc_int_consts] - pub const INFINITY: Self = 1.0 / 0.0; - /// Negative infinity (−∞). - #[$assoc_int_consts] - pub const NEG_INFINITY: Self = -1.0 / 0.0; - - /// Maximum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - - /// Minimum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// This constant is equivalent to `-MAX_EXACT_INTEGER`. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - - /// The mask of the bit used to encode the sign of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// This bit is set when the sign is negative and unset when the sign is - /// positive. - /// If you only need to check whether a value is positive or negative, - /// [`is_sign_positive`] or [`is_sign_negative`] can be used. - /// - /// [`is_sign_positive`]: Self::is_sign_positive - /// [`is_sign_negative`]: Self::is_sign_negative - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let a_bits = a.to_bits(); - /// - /// assert_eq!(a_bits & sign_mask, 0x0); - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] - #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: $BitsT = $SIGN_MASK; - - /// The mask of the bits used to encode the exponent of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// Note that the exponent is stored as a biased value, with a bias of - #[doc = stringify!($exponent_bias)] - /// for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] - #[doc = concat!(" let bias = ", $exponent_bias, ";")] - #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] - #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] - /// } - /// - /// assert_eq!(get_exp(0.5), -1); - /// assert_eq!(get_exp(1.0), 0); - /// assert_eq!(get_exp(2.0), 1); - /// assert_eq!(get_exp(4.0), 2); - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - - /// The mask of the bits used to encode the mantissa of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// ```rust - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] - /// - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - /// - /// // multiplying a finite value by a power of 2 doesn't change its mantissa - /// // unless the result or initial value is not normal. - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let b = 4.0 * a; - /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); - /// - /// // The maximum and minimum values have a saturated significand - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; - - /// Minimum representable positive value (min subnormal) - const TINY_BITS: $BitsT = 0x1; - - /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; -} - #[doc(test(attr(allow(unused_features))))] impl f32 { float_impl! { diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 411afd965b717..8b2ec693b99c9 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -14,6 +14,7 @@ use crate::convert::{FloatToFloat, FloatToInt}; use crate::num::FpCategory; +use crate::num::float_macros::float_impl; use crate::panic::const_assert; use crate::{intrinsics, mem}; @@ -401,335 +402,6 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[rustc_macro_transparency = "semiopaque"] -pub(crate) macro float_impl( - Self = $SelfT:ty, - Bits = $BitsT:ty, - SignedBits = $SignedBitsT:ty, - // Constants - BITS = $BITS:literal, - MANTISSA_DIGITS = $MANTISSA_DIGITS:literal, - DIGITS = $DIGITS:literal, - EPSILON = $EPSILON:literal, - MIN = $MIN:literal, - MIN_POSITIVE = $MIN_POSITIVE:literal, - MAX = $MAX:literal, - MIN_EXP = $MIN_EXP:literal, - MAX_EXP = $MAX_EXP:literal, - MIN_10_EXP = $MIN_10_EXP:literal, - MAX_10_EXP = $MAX_10_EXP:literal, - SIGN_MASK = $SIGN_MASK:literal, - EXPONENT_MASK = $EXPONENT_MASK:literal, - MANTISSA_MASK = $MANTISSA_MASK:literal, - // Values for docs - exponent_bias = $exponent_bias:literal, - // Feature gates - assoc_int_consts = #[$assoc_int_consts:meta], - // Things needed for `f16`/`f128` doctests - $(feature = $feature:ident,)? - $(has_reliable_cfg = $has_reliable_cfg:ident,)? - $(has_reliable_math_cfg = $has_reliable_math_cfg:ident,)? -) { - - /// The radix or base of the internal representation of - #[doc = concat!("`", stringify!($SelfT), "`.")] - #[$assoc_int_consts] - pub const RADIX: u32 = 2; - - /// The size of this float type in bits. - #[unstable(feature = "float_bits_const", issue = "151073")] - pub const BITS: u32 = $BITS; - - /// Number of significant digits in base 2. - /// - /// Note that the size of the mantissa in the bitwise representation is one - /// smaller than this since the leading 1 is not stored explicitly. - #[$assoc_int_consts] - pub const MANTISSA_DIGITS: u32 = $MANTISSA_DIGITS; - - /// Approximate number of significant digits in base 10. - /// - /// This is the maximum x such that any decimal number with x - /// significant digits can be converted to - #[doc = concat!("`", stringify!($SelfT), "`")] - /// and back without loss. - /// - /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - pub const DIGITS: u32 = $DIGITS; - - /// [Machine epsilon] value for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// This is the difference between `1.0` and the next larger representable number. - /// - /// Equal to 21 − [`MANTISSA_DIGITS`]. - /// - /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_epsilon")] - pub const EPSILON: Self = $EPSILON; - - /// Smallest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to −[`MAX`]. - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MIN: Self = $MIN; - /// Smallest positive normal - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to 2[`MIN_EXP`] − 1. - /// - /// [`MIN_EXP`]: Self::MIN_EXP - #[$assoc_int_consts] - pub const MIN_POSITIVE: Self = $MIN_POSITIVE; - /// Largest finite - #[doc = concat!("`", stringify!($SelfT), "`")] - /// value. - /// - /// Equal to - /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. - /// - /// [`MANTISSA_DIGITS`]: Self::MANTISSA_DIGITS - /// [`MAX_EXP`]: Self::MAX_EXP - #[$assoc_int_consts] - pub const MAX: Self = $MAX; - - /// One greater than the minimum possible *normal* power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact minimum possible *normal* power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all normal numbers representable by this type are - /// greater than or equal to 0.5 × 2MIN_EXP. - #[$assoc_int_consts] - pub const MIN_EXP: i32 = $MIN_EXP; - /// One greater than the maximum possible power of 2 exponent - /// for a significand bounded by 1 ≤ x < 2 (i.e. the IEEE definition). - /// - /// This corresponds to the exact maximum possible power of 2 exponent - /// for a significand bounded by 0.5 ≤ x < 1 (i.e. the C definition). - /// In other words, all numbers representable by this type are - /// strictly less than 2MAX_EXP. - #[$assoc_int_consts] - pub const MAX_EXP: i32 = $MAX_EXP; - - /// Minimum x for which 10x is normal. - /// - /// Equal to ceil(log10 [`MIN_POSITIVE`]). - /// - /// [`MIN_POSITIVE`]: Self::MIN_POSITIVE - #[$assoc_int_consts] - pub const MIN_10_EXP: i32 = $MIN_10_EXP; - /// Maximum x for which 10x is normal. - /// - /// Equal to floor(log10 [`MAX`]). - /// - /// [`MAX`]: Self::MAX - #[$assoc_int_consts] - pub const MAX_10_EXP: i32 = $MAX_10_EXP; - - /// Not a Number (NaN). - /// - /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are - /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and - /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern) - /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more - /// info. - /// - /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions - /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is - /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary. - /// The concrete bit pattern may change across Rust versions and target platforms. - #[$assoc_int_consts] - #[rustc_diagnostic_item = concat!(stringify!($SelfT), "_nan")] - #[allow(clippy::eq_op, clippy::zero_divided_by_zero)] - pub const NAN: Self = 0.0 / 0.0; - /// Infinity (∞). - #[$assoc_int_consts] - pub const INFINITY: Self = 1.0 / 0.0; - /// Negative infinity (−∞). - #[$assoc_int_consts] - pub const NEG_INFINITY: Self = -1.0 / 0.0; - - /// Maximum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!("[`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let max_exact_int = ", stringify!($SelfT), "::MAX_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(max_exact_int, max_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(max_exact_int + 1, (max_exact_int + 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(max_exact_int + 2, (max_exact_int + 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Beyond `", stringify!($SelfT), "::MAX_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((max_exact_int + 1) as ", stringify!($SelfT), ", (max_exact_int + 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MAX_EXACT_INTEGER: $SignedBitsT = (1 << Self::MANTISSA_DIGITS) - 1; - - /// Minimum integer that can be represented exactly in an - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value, with no other integer converting to the same floating point value. - /// - /// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`, - /// there is a "one-to-one" mapping between - #[doc = concat!(" [`", stringify!($SignedBitsT), "`]")] - /// and - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// values. `MAX_EXACT_INTEGER + 1` also converts losslessly to - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// and back to - #[doc = concat!(" [`", stringify!($SignedBitsT), "`],")] - /// but `MAX_EXACT_INTEGER + 2` converts to the same - #[doc = concat!("[`", stringify!($SelfT), "`]")] - /// value (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a - /// "one-to-one" mapping. - /// - /// This constant is equivalent to `-MAX_EXACT_INTEGER`. - /// - /// [`MAX_EXACT_INTEGER`]: Self::MAX_EXACT_INTEGER - /// [`MIN_EXACT_INTEGER`]: Self::MIN_EXACT_INTEGER - /// ``` - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - /// #![feature(float_exact_integer_constants)] - /// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754 - /// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] { - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let min_exact_int = ", stringify!($SelfT), "::MIN_EXACT_INTEGER;")] - #[doc = concat!("assert_eq!(min_exact_int, min_exact_int as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_eq!(min_exact_int - 1, (min_exact_int - 1) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - #[doc = concat!("assert_ne!(min_exact_int - 2, (min_exact_int - 2) as ", stringify!($SelfT), " as ", stringify!($SignedBitsT), ");")] - /// - #[doc = concat!("// Below `", stringify!($SelfT), "::MIN_EXACT_INTEGER`, multiple integers can map to one float value")] - #[doc = concat!("assert_eq!((min_exact_int - 1) as ", stringify!($SelfT), ", (min_exact_int - 2) as ", stringify!($SelfT), ");")] - #[doc = concat!("# }" $(${ignore($has_reliable_cfg)}, "}")?)] - /// ``` - #[unstable(feature = "float_exact_integer_constants", issue = "152466")] - pub const MIN_EXACT_INTEGER: $SignedBitsT = -Self::MAX_EXACT_INTEGER; - - /// The mask of the bit used to encode the sign of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// This bit is set when the sign is negative and unset when the sign is - /// positive. - /// If you only need to check whether a value is positive or negative, - /// [`is_sign_positive`] or [`is_sign_negative`] can be used. - /// - /// [`is_sign_positive`]: Self::is_sign_positive - /// [`is_sign_negative`]: Self::is_sign_negative - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let sign_mask = ", stringify!($SelfT), "::SIGN_MASK;")] - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let a_bits = a.to_bits(); - /// - /// assert_eq!(a_bits & sign_mask, 0x0); - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_bits(a_bits ^ sign_mask), -a);")] - #[doc = concat!("assert_eq!(sign_mask, (-0.0", stringify!($SelfT), ").to_bits());")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const SIGN_MASK: $BitsT = $SIGN_MASK; - - /// The mask of the bits used to encode the exponent of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// Note that the exponent is stored as a biased value, with a bias of - #[doc = stringify!($exponent_bias)] - /// for - #[doc = concat!("`", stringify!($SelfT), "`.")] - /// - /// ``` - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("fn get_exp(a: ", stringify!($SelfT), ") -> ", stringify!($SignedBitsT), " {")] - #[doc = concat!(" let bias = ", $exponent_bias, ";")] - #[doc = concat!(" let biased = a.to_bits() & ", stringify!($SelfT), "::EXPONENT_MASK;")] - #[doc = concat!(" (biased >> (", stringify!($SelfT), "::MANTISSA_DIGITS - 1)).cast_signed() - bias")] - /// } - /// - /// assert_eq!(get_exp(0.5), -1); - /// assert_eq!(get_exp(1.0), 0); - /// assert_eq!(get_exp(2.0), 1); - /// assert_eq!(get_exp(4.0), 2); - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const EXPONENT_MASK: $BitsT = $EXPONENT_MASK; - - /// The mask of the bits used to encode the mantissa of an - #[doc = concat!("[`", stringify!($SelfT), "`].")] - /// - /// ```rust - /// #![feature(float_masks)] - $(#[doc = concat!("#![feature(", stringify!($feature), ")]")])? - $(#[doc = concat!("# #[cfg(", stringify!($has_reliable_cfg), ")] {")])? - #[doc = concat!("let mantissa_mask = ", stringify!($SelfT), "::MANTISSA_MASK;")] - /// - #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".to_bits() & mantissa_mask, 0x0);")] - /// - /// // multiplying a finite value by a power of 2 doesn't change its mantissa - /// // unless the result or initial value is not normal. - #[doc = concat!("let a = 1.6552", stringify!($SelfT), ";")] - /// let b = 4.0 * a; - /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); - /// - /// // The maximum and minimum values have a saturated significand - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.to_bits() & ", stringify!($SelfT), "::MANTISSA_MASK, ", stringify!($SelfT), "::MANTISSA_MASK);")] - $(${ignore($has_reliable_cfg)} - /// # } - )? - /// ``` - #[unstable(feature = "float_masks", issue = "154064")] - pub const MANTISSA_MASK: $BitsT = $MANTISSA_MASK; - - /// Minimum representable positive value (min subnormal) - const TINY_BITS: $BitsT = 0x1; - - /// Minimum representable negative value (min negative subnormal) - const NEG_TINY_BITS: $BitsT = Self::TINY_BITS | Self::SIGN_MASK; -} - #[doc(test(attr(allow(unused_features))))] impl f64 { float_impl! { diff --git a/library/core/src/num/float_macros.rs b/library/core/src/num/float_macros.rs index 36580a17e7c5e..6795fa3ff56f9 100644 --- a/library/core/src/num/float_macros.rs +++ b/library/core/src/num/float_macros.rs @@ -1,4 +1,3 @@ -#[expect(unused_macros)] #[rustc_macro_transparency = "semiopaque"] pub(crate) macro float_impl( Self = $SelfT:ty, From afd0f73f6204b1b0430cdae4db56d51974cc1b47 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sun, 25 Oct 2026 17:15:48 +0100 Subject: [PATCH 03/29] feat: improve Cell doc Co-authored-by: Mark Rousskov --- library/core/src/cell.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d37f0eaa512a6..e51bc200089b6 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -11,19 +11,21 @@ //! mutate it. //! //! Shareable mutable containers exist to permit mutability in a controlled manner, even in the -//! presence of aliasing. [`Cell`], [`RefCell`], and [`OnceCell`] allow doing this in -//! a single-threaded way—they do not implement [`Sync`]. (If you need to do aliasing and -//! mutation among multiple threads, [`Mutex`], [`RwLock`], [`OnceLock`] or [`atomic`] -//! types are the correct data structures to do so). +//! presence of aliasing. The cell types in this module allow this from a single +//! thread (as enforced by not implementing [`Sync`]). +//! If you need to mutate while sharing across threads, each cell type has a +//! corresponding [`std::sync`] type that you can use. See also [`atomic`] types +//! which provide cross thread shared mutability for primitive types. //! -//! Values of the `Cell`, `RefCell`, and `OnceCell` types may be mutated through shared -//! references (i.e. the common `&T` type), whereas most Rust types can only be mutated through -//! unique (`&mut T`) references. We say these cell types provide 'interior mutability' -//! (mutable via `&T`), in contrast with typical Rust types that exhibit 'inherited mutability' -//! (mutable only via `&mut T`). +//! Values of the cell types types may be mutated through shared references (i.e. the common `&T` +//! type), whereas most Rust types can only be mutated through unique (`&mut T`) references. +//! We say these cell types provide 'interior mutability' (mutable via `&T`), in contrast with +//! typical Rust types that exhibit 'inherited mutability' (mutable only via `&mut T`). //! -//! Cell types come in four flavors: `Cell`, `RefCell`, `OnceCell`, and `LazyCell`. -//! Each provides a different way of providing safe interior mutability. +//! Cell types come in four flavors: `Cell`, `RefCell`, `OnceCell`, and +//! `LazyCell`. Each provides a different way of providing safe interior mutability. +//! +//! [`std::sync`]: ../sync/index.html //! //! ## `Cell` //! From c3f56a0793aff94179a5c837334e439efa861cf0 Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Tue, 27 Oct 2026 12:27:12 +0800 Subject: [PATCH 04/29] Add safety section for from_utf8_unchecked/from_raw_parts --- library/core/src/str/converts.rs | 6 ++++++ library/core/src/str/mod.rs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 6da9dce2d8707..5f458d021ab5d 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -186,6 +186,8 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { /// /// This is an alias to [`str::from_utf8_unchecked_mut`]. /// +/// # Safety +/// /// See the immutable version, [`from_utf8_unchecked()`] for documentation and safety requirements. /// /// # Examples @@ -219,6 +221,8 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { /// If this might not be the case, use `str::from_utf8(slice::from_raw_parts(ptr, len))`, /// which will return an `Err` if the data isn't valid UTF-8. /// +/// # Safety +/// /// This function is the `str` equivalent of [`slice::from_raw_parts`](crate::slice::from_raw_parts). /// See that function's documentation for safety concerns and examples. /// @@ -237,6 +241,8 @@ pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { /// If this might not be the case, use `str::from_utf8_mut(slice::from_raw_parts_mut(ptr, len))`, /// which will return an `Err` if the data isn't valid UTF-8. /// +/// # Safety +/// /// This function is the `str` equivalent of [`slice::from_raw_parts_mut`](crate::slice::from_raw_parts_mut). /// See that function's documentation for safety concerns and examples. /// diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 017d3f50eba32..68257bf931926 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -323,6 +323,8 @@ impl str { /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8; mutable version. /// + /// # Safety + /// /// See the immutable version, [`from_utf8_unchecked()`] for documentation and safety requirements. /// /// # Examples From a307a2f5d9da74fa6057470b546193f7d5179cf2 Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <68061195+yashaggarwal85d@users.noreply.github.com> Date: Tue, 27 Oct 2026 10:40:12 +0000 Subject: [PATCH 05/29] Suggest `gca!` for path const args that use generic params --- .../src/hir_ty_lowering/mod.rs | 63 ++++++++++++++++++- .../gca/no-gca-macro-suggestion.rs | 46 ++++++++++++++ .../gca/no-gca-macro-suggestion.stderr | 55 ++++++++++++++++ .../gca/suggest-gca-macro-for-path.fixed | 36 +++++++++++ .../gca/suggest-gca-macro-for-path.rs | 36 +++++++++++ .../gca/suggest-gca-macro-for-path.stderr | 62 ++++++++++++++++++ 6 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 tests/ui/const-generics/gca/no-gca-macro-suggestion.rs create mode 100644 tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr create mode 100644 tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed create mode 100644 tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs create mode 100644 tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 65db947b4cf50..3b9682ddc470a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -441,7 +441,14 @@ impl<'tcx> ForbidParamUsesFolder<'tcx> { } } if matches!(self.context, ForbidParamContext::ConstArgument) { - if self.tcx.features().gca_const_items() { + if let Some((span, path)) = self.gca_macro_suggestion() { + diag.span_suggestion_verbose( + span, + format!("consider wrapping `{path}` in the `gca!` macro"), + format!("gca!({path})"), + Applicability::MaybeIncorrect, + ); + } else if self.tcx.features().gca_const_items() { diag.help("consider factoring the expression into a `type const` item and use it as the const argument instead"); } else if self.tcx.features().gca_min_const_items() { diag.help("add `#![feature(gca_const_items)]` and extract the expression into a `type const` item"); @@ -454,6 +461,60 @@ impl<'tcx> ForbidParamUsesFolder<'tcx> { } diag.emit_err() } + + // If the anon const is just a path, it can be written as `gca!(path)` instead. + fn gca_macro_suggestion(&self) -> Option<(Span, String)> { + if !self.tcx.features().gca_min_const_items() || !self.tcx.features().gca_const_items() { + return None; + } + let anon_const_def_id = self.tcx.typeck_root_def_id_local(self.anon_const_def_id); + let hir::Node::AnonConst(anon_const) = self.tcx.hir_node_by_def_id(anon_const_def_id) + else { + return None; + }; + // Skip explicit `const { .. }` blocks, whose const arg span is wider than the body. + let hir::Node::ConstArg(const_arg) = self.tcx.parent_hir_node(anon_const.hir_id) else { + return None; + }; + let body = self.tcx.hir_body(anon_const.body).value; + if const_arg.span != body.span { + return None; + } + let mut expr = body; + while let hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(inner), .. }, None) = + expr.kind + { + expr = inner; + } + // `Ty::ASSOC` only works in `gca!` when `Ty` is a type parameter, as inherent + // associated consts would need `inherent_associated_types`. + match expr.kind { + hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: Res::Def(DefKind::Const | DefKind::AssocConst, _), .. }, + )) => {} + hir::ExprKind::Path(hir::QPath::TypeRelative( + hir::Ty { + kind: + hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { + res: Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. }, + .. + }, + )), + .. + }, + _, + )) => {} + _ => return None, + } + if !body.span.can_be_used_for_suggestions() { + return None; + } + let path = self.tcx.sess.source_map().span_to_snippet(expr.span).ok()?; + Some((body.span, path)) + } } impl<'tcx> ty::TypeFolder> for ForbidParamUsesFolder<'tcx> { diff --git a/tests/ui/const-generics/gca/no-gca-macro-suggestion.rs b/tests/ui/const-generics/gca/no-gca-macro-suggestion.rs new file mode 100644 index 0000000000000..237fbbbf7a10b --- /dev/null +++ b/tests/ui/const-generics/gca/no-gca-macro-suggestion.rs @@ -0,0 +1,46 @@ +//@ compile-flags: -Znext-solver +#![feature(gca_min_const_items, gca_const_items, generic_const_items)] +#![expect(incomplete_features)] + +use std::gca; + +pub trait Trait { + const N: usize; + fn foo() -> [u8; Self::N + 1]; + //~^ ERROR generic parameters in const blocks are not allowed +} + +struct S; + +fn bar() -> S { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +const FOO: usize = gca!(const { N }); +//~^ ERROR generic parameters in const blocks are not allowed + +struct W(T); + +impl W { + const M: usize = 1; + fn baz() -> [u8; Self::M] { + //~^ ERROR generic `Self` types are currently not permitted in anonymous constants + todo!() + } + fn qux() -> [u8; W::::M] { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() + } +} + +macro_rules! len { + ($t:ty) => { [u8; <$t as Trait>::N] }; +} + +fn quux() -> len!(T) { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +fn main() {} diff --git a/tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr b/tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr new file mode 100644 index 0000000000000..53d64b72d8c83 --- /dev/null +++ b/tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr @@ -0,0 +1,55 @@ +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/no-gca-macro-suggestion.rs:15:33 + | +LL | fn bar() -> S { + | ^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/no-gca-macro-suggestion.rs:20:49 + | +LL | const FOO: usize = gca!(const { N }); + | ^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/no-gca-macro-suggestion.rs:41:29 + | +LL | fn quux() -> len!(T) { + | ^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/no-gca-macro-suggestion.rs:27:22 + | +LL | fn baz() -> [u8; Self::M] { + | ^^^^ + | +note: not a concrete type + --> $DIR/no-gca-macro-suggestion.rs:25:9 + | +LL | impl W { + | ^^^^ + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/no-gca-macro-suggestion.rs:31:26 + | +LL | fn qux() -> [u8; W::::M] { + | ^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/no-gca-macro-suggestion.rs:9:22 + | +LL | fn foo() -> [u8; Self::N + 1]; + | ^^^^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed new file mode 100644 index 0000000000000..96506d3556c5e --- /dev/null +++ b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed @@ -0,0 +1,36 @@ +//@ run-rustfix +//@ compile-flags: -Znext-solver +#![feature(gca_min_const_items, gca_const_items, generic_const_items)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::gca; + +pub trait Trait { + const N: usize; + fn foo() -> [u8; gca!(Self::N)]; + //~^ ERROR generic parameters in const blocks are not allowed + fn bar() -> [u8; gca!(::N)]; + //~^ ERROR generic parameters in const blocks are not allowed +} + +struct S; + +fn baz() -> [u8; gca!(T::N)] { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +fn qux() -> S { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +const ID: usize = N; + +fn quux() -> [u8; gca!(ID::)] { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +fn main() {} diff --git a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs new file mode 100644 index 0000000000000..f386f9cb82aba --- /dev/null +++ b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs @@ -0,0 +1,36 @@ +//@ run-rustfix +//@ compile-flags: -Znext-solver +#![feature(gca_min_const_items, gca_const_items, generic_const_items)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::gca; + +pub trait Trait { + const N: usize; + fn foo() -> [u8; Self::N]; + //~^ ERROR generic parameters in const blocks are not allowed + fn bar() -> [u8; ::N]; + //~^ ERROR generic parameters in const blocks are not allowed +} + +struct S; + +fn baz() -> [u8; T::N] { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +fn qux() -> S<{ T::N }> { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +const ID: usize = N; + +fn quux() -> [u8; ID::] { + //~^ ERROR generic parameters in const blocks are not allowed + todo!() +} + +fn main() {} diff --git a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr new file mode 100644 index 0000000000000..b90c24ab67b13 --- /dev/null +++ b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr @@ -0,0 +1,62 @@ +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/suggest-gca-macro-for-path.rs:19:28 + | +LL | fn baz() -> [u8; T::N] { + | ^ + | +help: consider wrapping `T::N` in the `gca!` macro + | +LL - fn baz() -> [u8; T::N] { +LL + fn baz() -> [u8; gca!(T::N)] { + | + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/suggest-gca-macro-for-path.rs:24:27 + | +LL | fn qux() -> S<{ T::N }> { + | ^ + | +help: consider wrapping `T::N` in the `gca!` macro + | +LL - fn qux() -> S<{ T::N }> { +LL + fn qux() -> S { + | + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/suggest-gca-macro-for-path.rs:31:40 + | +LL | fn quux() -> [u8; ID::] { + | ^ + | +help: consider wrapping `ID::` in the `gca!` macro + | +LL - fn quux() -> [u8; ID::] { +LL + fn quux() -> [u8; gca!(ID::)] { + | + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/suggest-gca-macro-for-path.rs:11:22 + | +LL | fn foo() -> [u8; Self::N]; + | ^^^^ + | +help: consider wrapping `Self::N` in the `gca!` macro + | +LL - fn foo() -> [u8; Self::N]; +LL + fn foo() -> [u8; gca!(Self::N)]; + | + +error: generic parameters in const blocks are not allowed; use a named `const` item instead + --> $DIR/suggest-gca-macro-for-path.rs:13:23 + | +LL | fn bar() -> [u8; ::N]; + | ^^^^ + | +help: consider wrapping `::N` in the `gca!` macro + | +LL - fn bar() -> [u8; ::N]; +LL + fn bar() -> [u8; gca!(::N)]; + | + +error: aborting due to 5 previous errors + From ec550e6708541a38c59f7a9f3e27a35d92ce599c Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:30:24 +0330 Subject: [PATCH 06/29] Add regression test for overlap check hang with unresolved type in where clause --- ...n-where-clause-issue-152169.current.stderr | 22 +++++++++++++++++++ ...e-in-where-clause-issue-152169.next.stderr | 22 +++++++++++++++++++ ...error-type-in-where-clause-issue-152169.rs | 18 +++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.current.stderr create mode 100644 tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.next.stderr create mode 100644 tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.rs diff --git a/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.current.stderr b/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.current.stderr new file mode 100644 index 0000000000000..099cff23f1481 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.current.stderr @@ -0,0 +1,22 @@ +error[E0425]: cannot find type `Undefined` in this scope + --> $DIR/hang-on-error-type-in-where-clause-issue-152169.rs:12:28 + | +LL | impl Trait for T where (Undefined, T): Trait {} + | ^^^^^^^^^ not found in this scope + +error[E0119]: conflicting implementations of trait `Trait` for type `(_, _)` + --> $DIR/hang-on-error-type-in-where-clause-issue-152169.rs:15:1 + | +LL | impl Trait for T where (Undefined, T): Trait {} + | ----------------------------------------------- first implementation here +... +LL | impl Trait for (T, W) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)` + | + = note: overflow evaluating the requirement `({type error}, (_, _)): Trait` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hang_on_error_type_in_where_clause_issue_152169`) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0425. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.next.stderr b/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.next.stderr new file mode 100644 index 0000000000000..099cff23f1481 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.next.stderr @@ -0,0 +1,22 @@ +error[E0425]: cannot find type `Undefined` in this scope + --> $DIR/hang-on-error-type-in-where-clause-issue-152169.rs:12:28 + | +LL | impl Trait for T where (Undefined, T): Trait {} + | ^^^^^^^^^ not found in this scope + +error[E0119]: conflicting implementations of trait `Trait` for type `(_, _)` + --> $DIR/hang-on-error-type-in-where-clause-issue-152169.rs:15:1 + | +LL | impl Trait for T where (Undefined, T): Trait {} + | ----------------------------------------------- first implementation here +... +LL | impl Trait for (T, W) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)` + | + = note: overflow evaluating the requirement `({type error}, (_, _)): Trait` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hang_on_error_type_in_where_clause_issue_152169`) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0425. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.rs b/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.rs new file mode 100644 index 0000000000000..a6d44bc036535 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/hang-on-error-type-in-where-clause-issue-152169.rs @@ -0,0 +1,18 @@ +//! Regression test for . +//! +//! An unresolved type in the where clause of a blanket impl used to make +//! the overlap check hang. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Trait {} + +impl Trait for T where (Undefined, T): Trait {} +//~^ ERROR cannot find type `Undefined` in this scope + +impl Trait for (T, W) {} +//~^ ERROR conflicting implementations of trait `Trait` for type `(_, _)` + +fn main() {} From 63f21c83259e46f419f4dbb5bcc7e722ec11ff54 Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Wed, 21 Oct 2026 14:55:35 +0330 Subject: [PATCH 07/29] Add regression test for new solver hang on cyclic projection bound --- ...rojection-bound-hang-151723.current.stderr | 89 +++++++++++++++++++ ...c-projection-bound-hang-151723.next.stderr | 47 ++++++++++ .../wf-cyclic-projection-bound-hang-151723.rs | 38 ++++++++ 3 files changed, 174 insertions(+) create mode 100644 tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.current.stderr create mode 100644 tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.next.stderr create mode 100644 tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.rs diff --git a/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.current.stderr b/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.current.stderr new file mode 100644 index 0000000000000..61857b9275193 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.current.stderr @@ -0,0 +1,89 @@ +error[E0275]: overflow evaluating the requirement `NoopNewtype>>>>>>: Sized` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`wf_cyclic_projection_bound_hang_151723`) +note: required for `NoopNewtype>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `Noop` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:25:9 + | +LL | impl Noop for NoopNewtype {} + | - ^^^^ ^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound implicitly introduced here + = note: 126 redundant requirements hidden + = note: required for `Self` to implement `Noop` + +error[E0119]: conflicting implementations of trait `Noop` for type `NoopNewtype<_>` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:25:1 + | +LL | / impl Noop for T +LL | | +LL | | where +LL | | as Noop>::Assoc: Noop, + | |__________________________________________- first implementation here +... +LL | impl Noop for NoopNewtype {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoopNewtype<_>` + +error[E0275]: overflow evaluating the requirement `NoopNewtype>>>>>>: Sized` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:16:1 + | +LL | / impl Noop for T +LL | | +LL | | where +LL | | as Noop>::Assoc: Noop, + | |__________________________________________^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`wf_cyclic_projection_bound_hang_151723`) +note: required for `NoopNewtype>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `Noop` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:25:9 + | +LL | impl Noop for NoopNewtype {} + | - ^^^^ ^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound implicitly introduced here + = note: 126 redundant requirements hidden + = note: required for `NoopNewtype` to implement `Noop` + +error[E0275]: overflow evaluating the requirement `NoopNewtype>>>>>>: Sized` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:28:38 + | +LL | struct NoopNewtype(T::Assoc); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`wf_cyclic_projection_bound_hang_151723`) +note: required for `NoopNewtype>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `Noop` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:25:9 + | +LL | impl Noop for NoopNewtype {} + | - ^^^^ ^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound implicitly introduced here + = note: 126 redundant requirements hidden + = note: required for `T` to implement `Noop` + +error[E0275]: overflow evaluating the requirement `NoopNewtype>>>>>>: Sized` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:31:24 + | +LL | fn coerce_newtype() -> NoopNewtype { + | ^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`wf_cyclic_projection_bound_hang_151723`) +note: required for `NoopNewtype>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` to implement `Noop` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:25:9 + | +LL | impl Noop for NoopNewtype {} + | - ^^^^ ^^^^^^^^^^^^^^ + | | + | unsatisfied trait bound implicitly introduced here + = note: 125 redundant requirements hidden + = note: required for `str` to implement `Noop` +note: required because it appears within the type `NoopNewtype` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:28:8 + | +LL | struct NoopNewtype(T::Assoc); + | ^^^^^^^^^^^ + = note: the return type of a function must have a statically known size + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0119, E0275. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.next.stderr b/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.next.stderr new file mode 100644 index 0000000000000..99036c07c2bef --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.next.stderr @@ -0,0 +1,47 @@ +error[E0119]: conflicting implementations of trait `Noop` for type `NoopNewtype<_>` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:25:1 + | +LL | / impl Noop for T +LL | | +LL | | where +LL | | as Noop>::Assoc: Noop, + | |__________________________________________- first implementation here +... +LL | impl Noop for NoopNewtype {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoopNewtype<_>` + +error[E0275]: overflow evaluating the requirement ` as Noop>::Assoc == _` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:16:1 + | +LL | / impl Noop for T +LL | | +LL | | where +LL | | as Noop>::Assoc: Noop, + | |__________________________________________^ + +error[E0275]: overflow evaluating the requirement `NoopNewtype: Sized` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:31:24 + | +LL | fn coerce_newtype() -> NoopNewtype { + | ^^^^^^^^^^^^^^^^ + | + = note: the return type of a function must have a statically known size + +error[E0275]: overflow evaluating whether `NoopNewtype` is well-formed + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:31:24 + | +LL | fn coerce_newtype() -> NoopNewtype { + | ^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement ` as Noop>::Assoc == _` + --> $DIR/wf-cyclic-projection-bound-hang-151723.rs:21:5 + | +LL | type Assoc = T; + | ^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `::Assoc == _` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0119, E0275. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.rs b/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.rs new file mode 100644 index 0000000000000..425e56641895d --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/wf-cyclic-projection-bound-hang-151723.rs @@ -0,0 +1,38 @@ +//@ revisions: current next +//[current]~^ ERROR overflow evaluating the requirement +//[next]~^^ ERROR overflow evaluating the requirement `::Assoc == _` +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . +// +// Checking whether `NoopNewtype` is well-formed used to hang +// with the new solver. The hang was fixed by #163496. + +trait Noop { + type Assoc: ?Sized; +} + +impl Noop for T +//~^ ERROR overflow evaluating the requirement +where + as Noop>::Assoc: Noop, +{ + type Assoc = T; + //[next]~^ ERROR overflow evaluating the requirement ` as Noop>::Assoc == _` +} + +impl Noop for NoopNewtype {} +//~^ ERROR conflicting implementations of trait `Noop` for type `NoopNewtype<_>` + +struct NoopNewtype(T::Assoc); +//[current]~^ ERROR overflow evaluating the requirement + +fn coerce_newtype() -> NoopNewtype { + //[current]~^ ERROR overflow evaluating the requirement + //[next]~^^ ERROR overflow evaluating the requirement `NoopNewtype: Sized` + //[next]~^^^ ERROR overflow evaluating whether `NoopNewtype` is well-formed + todo!() +} + +fn main() {} From 8d6618b9120f1c94943927777d44dc1957d0a746 Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <68061195+yashaggarwal85d@users.noreply.github.com> Date: Thu, 29 Oct 2026 13:51:58 +0000 Subject: [PATCH 08/29] Reword gca help that still mentions removed `type const` items --- .../src/hir_ty_lowering/mod.rs | 69 ++----------------- compiler/rustc_resolve/src/diagnostics/mod.rs | 6 +- ...ociated-const-type-parameter-arrays.stderr | 2 +- tests/ui/associated-consts/issue-47814.stderr | 2 +- .../associated-item-duplicate-bounds.stderr | 2 +- .../index-oob-ice-83993.stderr | 4 +- .../const-arg-in-const-arg.min.stderr | 46 ++++++------- .../const-argument-if-length.min.stderr | 2 +- ...st-argument-non-static-lifetime.min.stderr | 2 +- .../complex-generic-default-expr.min.stderr | 4 +- ...const_arg_trivial_macro_expansion-4.stderr | 6 +- .../early/macro_rules-braces.stderr | 8 +-- ...ial-const-arg-macro-nested-braces-2.stderr | 2 +- ...ivial-const-arg-macro-nested-braces.stderr | 2 +- .../trivial-const-arg-nested-braces.stderr | 2 +- .../gca/gca-anon-const-rejected.stderr | 2 +- .../gca/generic-param-rhs.stderr | 2 +- .../gca/no-gca-macro-suggestion.rs | 46 ------------- .../gca/no-gca-macro-suggestion.stderr | 55 --------------- .../gca/rhs-but-not-root.stderr | 2 +- ...suggest-const-item-for-generic-expr.stderr | 6 +- .../gca/suggest-gca-macro-for-path.fixed | 36 ---------- .../gca/suggest-gca-macro-for-path.rs | 36 ---------- .../gca/suggest-gca-macro-for-path.stderr | 62 ----------------- ...ay-size-in-generic-struct-param.min.stderr | 4 +- .../generic_const_exprs/bad-multiply.stderr | 2 +- .../dependence_lint.full.stderr | 4 +- ...bute-missing-in-dependent-crate-ice.stderr | 2 +- .../feature-gate-generic_const_exprs.stderr | 2 +- .../issue-72787.min.stderr | 8 +-- ...sue-72819-generic-in-const-eval.min.stderr | 2 +- .../generic_const_exprs/issue-74713.stderr | 2 +- .../trivial-anon-const-use-cases.min.stderr | 2 +- tests/ui/const-generics/ice-68875.stderr | 2 +- ...ics-type_name-as-const-argument.min.stderr | 2 +- tests/ui/const-generics/issue-46511.stderr | 2 +- .../issues/issue-56445-2.stderr | 2 +- .../issues/issue-56445-3.stderr | 2 +- .../issues/issue-67375.min.stderr | 2 +- .../issues/issue-67945-1.min.stderr | 4 +- .../issues/issue-67945-2.min.stderr | 2 +- .../issues/issue-67945-3.min.stderr | 2 +- .../issues/issue-67945-4.min.stderr | 2 +- .../issues/issue-68366.min.stderr | 2 +- .../issue-76701-ty-param-in-const.stderr | 4 +- .../const-generics/issues/issue-80062.stderr | 2 +- .../const-generics/issues/issue-80375.stderr | 2 +- .../legacy-const-generics-bad.stderr | 2 +- .../mgca/adt_expr_arg_simple.stderr | 2 +- ...st-param-in-nested-inline-const-arg.stderr | 2 +- .../mgca/double-inline-const.stderr | 2 +- ...ed-path-not-accidentally-stabilized.stderr | 2 +- .../mgca/early-bound-param-lt-bad.stderr | 2 +- .../mgca/explicit_anon_consts.stderr | 14 ++-- .../mgca/gca-macro-feature-gate.stderr | 2 +- ...-direct-anon-expression-diagnostics.stderr | 2 +- .../mgca/selftyalias-containing-param.stderr | 2 +- .../ui/const-generics/mgca/selftyparam.stderr | 2 +- .../size-of-generic-ptr-in-array-len.stderr | 2 +- .../mgca/tuple_ctor_complex_args.stderr | 2 +- .../mgca/tuple_expr_arg_complex.stderr | 2 +- .../mgca/type_const-on-generic-expr.stderr | 4 +- .../mgca/type_const-on-generic_expr-2.stderr | 6 +- .../complex-expression.stderr | 14 ++-- .../forbid-non-static-lifetimes.stderr | 4 +- .../forbid-self-no-normalize.stderr | 2 +- .../self-ty-in-const-1.stderr | 4 +- .../self-ty-in-const-2.stderr | 2 +- ...r-lifetime-in-const-generic-default.stderr | 2 +- ...ams-in-ct-in-ty-param-lazy-norm.min.stderr | 2 +- tests/ui/const-generics/paren.stderr | 10 +-- ...peat_expr_hack_gives_right_generics.stderr | 4 +- .../type-relative-path-144547.min.stderr | 2 +- tests/ui/consts/const-eval/size-of-t.stderr | 2 +- .../feature-gate-gca-const-items.stderr | 2 +- .../feature-gate-gca-macroless-args.stderr | 2 +- .../feature-gate-gca-min-const-items.stderr | 2 +- .../param-in-ct-in-ty-param-default.stderr | 2 +- .../issue-64173-unused-lifetimes.stderr | 4 +- tests/ui/resolve/issue-39559.stderr | 2 +- .../pattern_types/assoc_const.default.stderr | 8 +-- 81 files changed, 144 insertions(+), 442 deletions(-) delete mode 100644 tests/ui/const-generics/gca/no-gca-macro-suggestion.rs delete mode 100644 tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr delete mode 100644 tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed delete mode 100644 tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs delete mode 100644 tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3b9682ddc470a..6a0fb57eff1bd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -441,80 +441,19 @@ impl<'tcx> ForbidParamUsesFolder<'tcx> { } } if matches!(self.context, ForbidParamContext::ConstArgument) { - if let Some((span, path)) = self.gca_macro_suggestion() { - diag.span_suggestion_verbose( - span, - format!("consider wrapping `{path}` in the `gca!` macro"), - format!("gca!({path})"), - Applicability::MaybeIncorrect, - ); - } else if self.tcx.features().gca_const_items() { - diag.help("consider factoring the expression into a `type const` item and use it as the const argument instead"); + if self.tcx.features().gca_const_items() { + diag.help("consider wrapping the expression in the `gca!` macro"); } else if self.tcx.features().gca_min_const_items() { - diag.help("add `#![feature(gca_const_items)]` and extract the expression into a `type const` item"); + diag.help("add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro"); } else if self.tcx.sess.is_nightly_build() { diag.help( "add `#![feature(generic_const_exprs)]` to allow generic const expressions", ); - diag.help("alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item"); + diag.help("alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro"); } } diag.emit_err() } - - // If the anon const is just a path, it can be written as `gca!(path)` instead. - fn gca_macro_suggestion(&self) -> Option<(Span, String)> { - if !self.tcx.features().gca_min_const_items() || !self.tcx.features().gca_const_items() { - return None; - } - let anon_const_def_id = self.tcx.typeck_root_def_id_local(self.anon_const_def_id); - let hir::Node::AnonConst(anon_const) = self.tcx.hir_node_by_def_id(anon_const_def_id) - else { - return None; - }; - // Skip explicit `const { .. }` blocks, whose const arg span is wider than the body. - let hir::Node::ConstArg(const_arg) = self.tcx.parent_hir_node(anon_const.hir_id) else { - return None; - }; - let body = self.tcx.hir_body(anon_const.body).value; - if const_arg.span != body.span { - return None; - } - let mut expr = body; - while let hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(inner), .. }, None) = - expr.kind - { - expr = inner; - } - // `Ty::ASSOC` only works in `gca!` when `Ty` is a type parameter, as inherent - // associated consts would need `inherent_associated_types`. - match expr.kind { - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: Res::Def(DefKind::Const | DefKind::AssocConst, _), .. }, - )) => {} - hir::ExprKind::Path(hir::QPath::TypeRelative( - hir::Ty { - kind: - hir::TyKind::Path(hir::QPath::Resolved( - None, - hir::Path { - res: Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. }, - .. - }, - )), - .. - }, - _, - )) => {} - _ => return None, - } - if !body.span.can_be_used_for_suggestions() { - return None; - } - let path = self.tcx.sess.source_map().span_to_snippet(expr.span).ok()?; - Some((body.span, path)) - } } impl<'tcx> ty::TypeFolder> for ForbidParamUsesFolder<'tcx> { diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index 65ef919e9d0c7..f665581daf10d 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -424,12 +424,10 @@ pub(crate) struct ParamInNonTrivialAnonConst { #[help("add `#![feature(generic_const_exprs)]` to allow generic const expressions")] pub(crate) help: bool, pub(crate) is_gca_const_items: bool, - #[help( - "consider factoring the expression into a `type const` item and use it as the const argument instead" - )] + #[help("consider wrapping the expression in the `gca!` macro")] pub(crate) help_gca: bool, #[help( - "alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item" + "alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro" )] pub(crate) help_suggest_gca: bool, } diff --git a/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr b/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr index b007bd6694628..8f03faa572161 100644 --- a/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr +++ b/tests/ui/associated-consts/associated-const-type-parameter-arrays.stderr @@ -6,7 +6,7 @@ LL | let _array: [u32; ::Y]; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/associated-consts/issue-47814.stderr b/tests/ui/associated-consts/issue-47814.stderr index 4d6efef3b82c0..42aeef4167178 100644 --- a/tests/ui/associated-consts/issue-47814.stderr +++ b/tests/ui/associated-consts/issue-47814.stderr @@ -10,7 +10,7 @@ note: not a concrete type LL | impl<'a> ArpIPv4<'a> { | ^^^^^^^^^^^ = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/associated-item/associated-item-duplicate-bounds.stderr b/tests/ui/associated-item/associated-item-duplicate-bounds.stderr index 60dbbcbe458fe..7472fd1f57e7f 100644 --- a/tests/ui/associated-item/associated-item-duplicate-bounds.stderr +++ b/tests/ui/associated-item/associated-item-duplicate-bounds.stderr @@ -6,7 +6,7 @@ LL | links: [u32; A::LINKS], // Shouldn't suggest bounds already there. | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr index e2b989c9c5d1e..d57d4a65229b5 100644 --- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr +++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr @@ -6,7 +6,7 @@ LL | let x: &'b (); | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/index-oob-ice-83993.rs:18:17 @@ -16,7 +16,7 @@ LL | let _: &'b (); | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index d5b5ad9d8dc15..08f543c48acaa 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -6,7 +6,7 @@ LL | let _: [u8; foo::()]; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:16:23 @@ -16,7 +16,7 @@ LL | let _: [u8; bar::()]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:17:23 @@ -26,7 +26,7 @@ LL | let _: [u8; faz::<'a>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:19:23 @@ -36,7 +36,7 @@ LL | let _: [u8; baz::<'a>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:20:23 @@ -46,7 +46,7 @@ LL | let _: [u8; faz::<'b>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:22:23 @@ -56,7 +56,7 @@ LL | let _: [u8; baz::<'b>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:26:23 @@ -66,7 +66,7 @@ LL | let _ = [0; bar::()]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:27:23 @@ -76,7 +76,7 @@ LL | let _ = [0; faz::<'a>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:29:23 @@ -86,7 +86,7 @@ LL | let _ = [0; baz::<'a>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:30:23 @@ -96,7 +96,7 @@ LL | let _ = [0; faz::<'b>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:32:23 @@ -106,7 +106,7 @@ LL | let _ = [0; baz::<'b>(&())]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:33:24 @@ -116,7 +116,7 @@ LL | let _: Foo<{ foo::() }>; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:34:24 @@ -126,7 +126,7 @@ LL | let _: Foo<{ bar::() }>; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:35:24 @@ -136,7 +136,7 @@ LL | let _: Foo<{ faz::<'a>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:37:24 @@ -146,7 +146,7 @@ LL | let _: Foo<{ baz::<'a>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:38:24 @@ -156,7 +156,7 @@ LL | let _: Foo<{ faz::<'b>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:40:24 @@ -166,7 +166,7 @@ LL | let _: Foo<{ baz::<'b>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:41:27 @@ -176,7 +176,7 @@ LL | let _ = Foo::<{ foo::() }>; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:42:27 @@ -186,7 +186,7 @@ LL | let _ = Foo::<{ bar::() }>; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:43:27 @@ -196,7 +196,7 @@ LL | let _ = Foo::<{ faz::<'a>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:45:27 @@ -206,7 +206,7 @@ LL | let _ = Foo::<{ baz::<'a>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:46:27 @@ -216,7 +216,7 @@ LL | let _ = Foo::<{ faz::<'b>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const-arg-in-const-arg.rs:48:27 @@ -226,7 +226,7 @@ LL | let _ = Foo::<{ baz::<'b>(&()) }>; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:17:23 diff --git a/tests/ui/const-generics/const-argument-if-length.min.stderr b/tests/ui/const-generics/const-argument-if-length.min.stderr index c52d79a6f67bf..886f34db11df5 100644 --- a/tests/ui/const-generics/const-argument-if-length.min.stderr +++ b/tests/ui/const-generics/const-argument-if-length.min.stderr @@ -6,7 +6,7 @@ LL | pad: [u8; is_zst::()], | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/const-argument-if-length.rs:16:12 diff --git a/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr b/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr index 21f7e72f7dcb7..5d882fe1c5b74 100644 --- a/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr +++ b/tests/ui/const-generics/const-argument-non-static-lifetime.min.stderr @@ -6,7 +6,7 @@ LL | let _: &'a (); | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr index a24200f54b170..3c9d7a066c829 100644 --- a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr +++ b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr @@ -6,7 +6,7 @@ LL | struct Foo; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-generic-default-expr.rs:9:62 @@ -16,7 +16,7 @@ LL | struct Bar() }>(T); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr index 2ad49111e26e6..7bc2aaef09868 100644 --- a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr +++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr @@ -11,7 +11,7 @@ LL | fn foo() -> Foo<{ arg!{} arg!{} }> { loop {} } | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const_arg_trivial_macro_expansion-4.rs:7:9 @@ -26,7 +26,7 @@ LL | fn foo() -> Foo<{ arg!{} arg!{} }> { loop {} } | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/const_arg_trivial_macro_expansion-4.rs:15:46 @@ -36,7 +36,7 @@ LL | fn bar() -> [(); { empty!{}; N }] { loop {} } | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/early/macro_rules-braces.stderr b/tests/ui/const-generics/early/macro_rules-braces.stderr index f5a300026a51b..6cc9a67f194b7 100644 --- a/tests/ui/const-generics/early/macro_rules-braces.stderr +++ b/tests/ui/const-generics/early/macro_rules-braces.stderr @@ -28,7 +28,7 @@ LL | let _: foo!({{ N }}); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:36:19 @@ -38,7 +38,7 @@ LL | let _: bar!({ N }); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:41:20 @@ -48,7 +48,7 @@ LL | let _: baz!({{ N }}); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:46:19 @@ -58,7 +58,7 @@ LL | let _: biz!({ N }); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr index 927f0af668fa3..4385e08cf6057 100644 --- a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr @@ -11,7 +11,7 @@ LL | fn foo() -> A<{{ y!() }}> { | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr index 5d5319d0b8af7..6c51d922ae759 100644 --- a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr @@ -11,7 +11,7 @@ LL | fn foo() -> A<{ y!() }> { | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr index 168661e6d85b4..657836530abd8 100644 --- a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr +++ b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr @@ -6,7 +6,7 @@ LL | fn foo() -> A<{ { N } }> { | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/gca/gca-anon-const-rejected.stderr b/tests/ui/const-generics/gca/gca-anon-const-rejected.stderr index 93d4c1ce76e39..c6e0664b759df 100644 --- a/tests/ui/const-generics/gca/gca-anon-const-rejected.stderr +++ b/tests/ui/const-generics/gca/gca-anon-const-rejected.stderr @@ -4,7 +4,7 @@ error: generic parameters in const blocks are not allowed; use a named `const` i LL | const FOO: usize = gca!(const { N + 1 }); | ^ | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead + = help: consider wrapping the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/gca/generic-param-rhs.stderr b/tests/ui/const-generics/gca/generic-param-rhs.stderr index e4b5e76dbabf3..5f008156067bd 100644 --- a/tests/ui/const-generics/gca/generic-param-rhs.stderr +++ b/tests/ui/const-generics/gca/generic-param-rhs.stderr @@ -4,7 +4,7 @@ error: generic parameters in const blocks are not allowed; use a named `const` i LL | foo::(); | ^ | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead + = help: consider wrapping the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/gca/no-gca-macro-suggestion.rs b/tests/ui/const-generics/gca/no-gca-macro-suggestion.rs deleted file mode 100644 index 237fbbbf7a10b..0000000000000 --- a/tests/ui/const-generics/gca/no-gca-macro-suggestion.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ compile-flags: -Znext-solver -#![feature(gca_min_const_items, gca_const_items, generic_const_items)] -#![expect(incomplete_features)] - -use std::gca; - -pub trait Trait { - const N: usize; - fn foo() -> [u8; Self::N + 1]; - //~^ ERROR generic parameters in const blocks are not allowed -} - -struct S; - -fn bar() -> S { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -const FOO: usize = gca!(const { N }); -//~^ ERROR generic parameters in const blocks are not allowed - -struct W(T); - -impl W { - const M: usize = 1; - fn baz() -> [u8; Self::M] { - //~^ ERROR generic `Self` types are currently not permitted in anonymous constants - todo!() - } - fn qux() -> [u8; W::::M] { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() - } -} - -macro_rules! len { - ($t:ty) => { [u8; <$t as Trait>::N] }; -} - -fn quux() -> len!(T) { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -fn main() {} diff --git a/tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr b/tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr deleted file mode 100644 index 53d64b72d8c83..0000000000000 --- a/tests/ui/const-generics/gca/no-gca-macro-suggestion.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/no-gca-macro-suggestion.rs:15:33 - | -LL | fn bar() -> S { - | ^ - | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/no-gca-macro-suggestion.rs:20:49 - | -LL | const FOO: usize = gca!(const { N }); - | ^ - | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/no-gca-macro-suggestion.rs:41:29 - | -LL | fn quux() -> len!(T) { - | ^ - | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead - -error: generic `Self` types are currently not permitted in anonymous constants - --> $DIR/no-gca-macro-suggestion.rs:27:22 - | -LL | fn baz() -> [u8; Self::M] { - | ^^^^ - | -note: not a concrete type - --> $DIR/no-gca-macro-suggestion.rs:25:9 - | -LL | impl W { - | ^^^^ - = help: consider factoring the expression into a `type const` item and use it as the const argument instead - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/no-gca-macro-suggestion.rs:31:26 - | -LL | fn qux() -> [u8; W::::M] { - | ^ - | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/no-gca-macro-suggestion.rs:9:22 - | -LL | fn foo() -> [u8; Self::N + 1]; - | ^^^^ - | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead - -error: aborting due to 6 previous errors - diff --git a/tests/ui/const-generics/gca/rhs-but-not-root.stderr b/tests/ui/const-generics/gca/rhs-but-not-root.stderr index d34d7f6b51a74..f7026c3173d6f 100644 --- a/tests/ui/const-generics/gca/rhs-but-not-root.stderr +++ b/tests/ui/const-generics/gca/rhs-but-not-root.stderr @@ -4,7 +4,7 @@ error: generic parameters in const blocks are not allowed; use a named `const` i LL | const FOO: usize = gca!(ID::); | ^ | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead + = help: consider wrapping the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/gca/suggest-const-item-for-generic-expr.stderr b/tests/ui/const-generics/gca/suggest-const-item-for-generic-expr.stderr index 27d6c5d4c8557..3cd0448a27f1a 100644 --- a/tests/ui/const-generics/gca/suggest-const-item-for-generic-expr.stderr +++ b/tests/ui/const-generics/gca/suggest-const-item-for-generic-expr.stderr @@ -6,7 +6,7 @@ LL | fn as_bytes(&self) -> &[u8; size_of::()] { | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/suggest-const-item-for-generic-expr.rs:16:31 @@ -16,7 +16,7 @@ LL | fn foo() -> [u8; size_of::()] { | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/suggest-const-item-for-generic-expr.rs:21:34 @@ -26,7 +26,7 @@ LL | fn bar() -> [u8; N + 1] { | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed deleted file mode 100644 index 96506d3556c5e..0000000000000 --- a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.fixed +++ /dev/null @@ -1,36 +0,0 @@ -//@ run-rustfix -//@ compile-flags: -Znext-solver -#![feature(gca_min_const_items, gca_const_items, generic_const_items)] -#![expect(incomplete_features)] -#![allow(dead_code)] - -use std::gca; - -pub trait Trait { - const N: usize; - fn foo() -> [u8; gca!(Self::N)]; - //~^ ERROR generic parameters in const blocks are not allowed - fn bar() -> [u8; gca!(::N)]; - //~^ ERROR generic parameters in const blocks are not allowed -} - -struct S; - -fn baz() -> [u8; gca!(T::N)] { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -fn qux() -> S { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -const ID: usize = N; - -fn quux() -> [u8; gca!(ID::)] { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -fn main() {} diff --git a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs deleted file mode 100644 index f386f9cb82aba..0000000000000 --- a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@ run-rustfix -//@ compile-flags: -Znext-solver -#![feature(gca_min_const_items, gca_const_items, generic_const_items)] -#![expect(incomplete_features)] -#![allow(dead_code)] - -use std::gca; - -pub trait Trait { - const N: usize; - fn foo() -> [u8; Self::N]; - //~^ ERROR generic parameters in const blocks are not allowed - fn bar() -> [u8; ::N]; - //~^ ERROR generic parameters in const blocks are not allowed -} - -struct S; - -fn baz() -> [u8; T::N] { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -fn qux() -> S<{ T::N }> { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -const ID: usize = N; - -fn quux() -> [u8; ID::] { - //~^ ERROR generic parameters in const blocks are not allowed - todo!() -} - -fn main() {} diff --git a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr b/tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr deleted file mode 100644 index b90c24ab67b13..0000000000000 --- a/tests/ui/const-generics/gca/suggest-gca-macro-for-path.stderr +++ /dev/null @@ -1,62 +0,0 @@ -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/suggest-gca-macro-for-path.rs:19:28 - | -LL | fn baz() -> [u8; T::N] { - | ^ - | -help: consider wrapping `T::N` in the `gca!` macro - | -LL - fn baz() -> [u8; T::N] { -LL + fn baz() -> [u8; gca!(T::N)] { - | - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/suggest-gca-macro-for-path.rs:24:27 - | -LL | fn qux() -> S<{ T::N }> { - | ^ - | -help: consider wrapping `T::N` in the `gca!` macro - | -LL - fn qux() -> S<{ T::N }> { -LL + fn qux() -> S { - | - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/suggest-gca-macro-for-path.rs:31:40 - | -LL | fn quux() -> [u8; ID::] { - | ^ - | -help: consider wrapping `ID::` in the `gca!` macro - | -LL - fn quux() -> [u8; ID::] { -LL + fn quux() -> [u8; gca!(ID::)] { - | - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/suggest-gca-macro-for-path.rs:11:22 - | -LL | fn foo() -> [u8; Self::N]; - | ^^^^ - | -help: consider wrapping `Self::N` in the `gca!` macro - | -LL - fn foo() -> [u8; Self::N]; -LL + fn foo() -> [u8; gca!(Self::N)]; - | - -error: generic parameters in const blocks are not allowed; use a named `const` item instead - --> $DIR/suggest-gca-macro-for-path.rs:13:23 - | -LL | fn bar() -> [u8; ::N]; - | ^^^^ - | -help: consider wrapping `::N` in the `gca!` macro - | -LL - fn bar() -> [u8; ::N]; -LL + fn bar() -> [u8; gca!(::N)]; - | - -error: aborting due to 5 previous errors - diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr index 15016c747d8a9..e64264a692dad 100644 --- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr @@ -6,7 +6,7 @@ LL | struct ArithArrayLen([u32; 0 + N]); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/array-size-in-generic-struct-param.rs:23:15 @@ -16,7 +16,7 @@ LL | arr: [u8; CFG.arr_size], | = help: const parameters may only be used as standalone arguments here, i.e. `CFG` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: `Config` is forbidden as the type of a const generic parameter --> $DIR/array-size-in-generic-struct-param.rs:21:21 diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr index e349ab78e4838..97fdd269ad76b 100644 --- a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr +++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr @@ -6,7 +6,7 @@ LL | SmallVec<{ D * 2 }>:, | = help: const parameters may only be used as standalone arguments here, i.e. `D` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0747]: constant provided when a type was expected --> $DIR/bad-multiply.rs:7:14 diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr index 05c8f1e945ccc..93db23b292e1b 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr @@ -6,7 +6,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/dependence_lint.rs:21:37 @@ -16,7 +16,7 @@ LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro warning: cannot use constants which depend on generic parameters in types --> $DIR/dependence_lint.rs:10:9 diff --git a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr index bd811c72e83d6..ae300adf01875 100644 --- a/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr +++ b/tests/ui/const-generics/generic_const_exprs/feature-attribute-missing-in-dependent-crate-ice.stderr @@ -10,7 +10,7 @@ note: not a concrete type LL | impl aux::FromSlice for Wrapper { | ^^^^^^^^^^ = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr index e2b74b61b2043..1a486dbd3e003 100644 --- a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr +++ b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr @@ -6,7 +6,7 @@ LL | type Arr = [u8; N - 1]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 15db638d1ae45..2ad11788d08e5 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -6,7 +6,7 @@ LL | Condition<{ LHS <= RHS }>: True | = help: const parameters may only be used as standalone arguments here, i.e. `LHS` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:24 @@ -16,7 +16,7 @@ LL | Condition<{ LHS <= RHS }>: True | = help: const parameters may only be used as standalone arguments here, i.e. `RHS` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:23:25 @@ -26,7 +26,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:23:36 @@ -36,7 +36,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | = help: const parameters may only be used as standalone arguments here, i.e. `J` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr index fa711a917a666..67bf2a65fa70e 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr @@ -6,7 +6,7 @@ LL | where Assert::<{N < usize::MAX / 2}>: IsTrue, | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr b/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr index 9d03a11fc581d..bd8fa37ea279e 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-74713.stderr @@ -6,7 +6,7 @@ LL | let _: &'a (); | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0308]: mismatched types --> $DIR/issue-74713.rs:3:10 diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr index 885cad3846ec3..ac2dc425d1805 100644 --- a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr @@ -6,7 +6,7 @@ LL | stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in t | = help: const parameters may only be used as standalone arguments here, i.e. `S` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/ice-68875.stderr b/tests/ui/const-generics/ice-68875.stderr index ca01b2e643143..03a855ff437e8 100644 --- a/tests/ui/const-generics/ice-68875.stderr +++ b/tests/ui/const-generics/ice-68875.stderr @@ -5,7 +5,7 @@ LL | data: &'a [u8; Self::SIZE], | ^^^^ | = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index d865ecb6275b2..10215143a12bf 100644 --- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -6,7 +6,7 @@ LL | T: Trait<{ std::intrinsics::type_name::() }>, | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/intrinsics-type_name-as-const-argument.rs:9:22 diff --git a/tests/ui/const-generics/issue-46511.stderr b/tests/ui/const-generics/issue-46511.stderr index 74a1eb5779289..ac61caaf6db28 100644 --- a/tests/ui/const-generics/issue-46511.stderr +++ b/tests/ui/const-generics/issue-46511.stderr @@ -6,7 +6,7 @@ LL | _a: [u8; std::mem::size_of::<&'a mut u8>()] | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: lifetime parameter `'a` is never used --> $DIR/issue-46511.rs:3:12 diff --git a/tests/ui/const-generics/issues/issue-56445-2.stderr b/tests/ui/const-generics/issues/issue-56445-2.stderr index fa9a0d83201a6..36407f45674f2 100644 --- a/tests/ui/const-generics/issues/issue-56445-2.stderr +++ b/tests/ui/const-generics/issues/issue-56445-2.stderr @@ -10,7 +10,7 @@ note: not a concrete type LL | impl<'a> OnDiskDirEntry<'a> { | ^^^^^^^^^^^^^^^^^^ = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-56445-3.stderr b/tests/ui/const-generics/issues/issue-56445-3.stderr index 4e5c491dbe8d0..9bdbb7f037728 100644 --- a/tests/ui/const-generics/issues/issue-56445-3.stderr +++ b/tests/ui/const-generics/issues/issue-56445-3.stderr @@ -5,7 +5,7 @@ LL | ram: [u8; Self::SIZE], | ^^^^ | = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-67375.min.stderr b/tests/ui/const-generics/issues/issue-67375.min.stderr index 757220e53dcac..41e2931cb7b66 100644 --- a/tests/ui/const-generics/issues/issue-67375.min.stderr +++ b/tests/ui/const-generics/issues/issue-67375.min.stderr @@ -6,7 +6,7 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }], | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: type parameter `T` is never used --> $DIR/issue-67375.rs:5:12 diff --git a/tests/ui/const-generics/issues/issue-67945-1.min.stderr b/tests/ui/const-generics/issues/issue-67945-1.min.stderr index a0c4676443b73..c71baba260974 100644 --- a/tests/ui/const-generics/issues/issue-67945-1.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-1.min.stderr @@ -6,7 +6,7 @@ LL | let x: S = MaybeUninit::uninit(); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:13:45 @@ -16,7 +16,7 @@ LL | let b = &*(&x as *const _ as *const S); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-1.rs:7:12 diff --git a/tests/ui/const-generics/issues/issue-67945-2.min.stderr b/tests/ui/const-generics/issues/issue-67945-2.min.stderr index adc2cd09d26dc..8df3d4ec42630 100644 --- a/tests/ui/const-generics/issues/issue-67945-2.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-2.min.stderr @@ -5,7 +5,7 @@ LL | let x: Option> = None; | ^^^^ | = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-67945-3.min.stderr b/tests/ui/const-generics/issues/issue-67945-3.min.stderr index 1ab37d3b2c466..a8ba4b359745a 100644 --- a/tests/ui/const-generics/issues/issue-67945-3.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-3.min.stderr @@ -6,7 +6,7 @@ LL | let x: Option = None; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-3.rs:9:12 diff --git a/tests/ui/const-generics/issues/issue-67945-4.min.stderr b/tests/ui/const-generics/issues/issue-67945-4.min.stderr index a6e3755088c92..831858a1261a1 100644 --- a/tests/ui/const-generics/issues/issue-67945-4.min.stderr +++ b/tests/ui/const-generics/issues/issue-67945-4.min.stderr @@ -6,7 +6,7 @@ LL | let x: Option> = None; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: type parameter `S` is never used --> $DIR/issue-67945-4.rs:8:12 diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr index 8d10b83b7bcb2..e5224acb976d1 100644 --- a/tests/ui/const-generics/issues/issue-68366.min.stderr +++ b/tests/ui/const-generics/issues/issue-68366.min.stderr @@ -6,7 +6,7 @@ LL | impl Collatz<{Some(N)}> {} | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: `Option` is forbidden as the type of a const generic parameter --> $DIR/issue-68366.rs:9:25 diff --git a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr index 6e00aa40f6014..77b7233fbc3c4 100644 --- a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr +++ b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr @@ -6,7 +6,7 @@ LL | fn ty_param() -> [u8; std::mem::size_of::()] { | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:6:42 @@ -16,7 +16,7 @@ LL | fn const_param() -> [u8; N + 1] { | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-80062.stderr b/tests/ui/const-generics/issues/issue-80062.stderr index 5d804bf8ef8b2..1738d22a0222c 100644 --- a/tests/ui/const-generics/issues/issue-80062.stderr +++ b/tests/ui/const-generics/issues/issue-80062.stderr @@ -6,7 +6,7 @@ LL | let _: [u8; sof::()]; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-80375.stderr b/tests/ui/const-generics/issues/issue-80375.stderr index d2adadad7ace4..af728e4edd6c7 100644 --- a/tests/ui/const-generics/issues/issue-80375.stderr +++ b/tests/ui/const-generics/issues/issue-80375.stderr @@ -6,7 +6,7 @@ LL | struct MyArray([u8; COUNT + 1]); | = help: const parameters may only be used as standalone arguments here, i.e. `COUNT` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 80d807c3f822a..d0b295d00741d 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -18,7 +18,7 @@ LL | legacy_const_generics::foo(0, N + 1, 2); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr index 70ed0cbc41f64..18163a5d90c52 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr @@ -10,7 +10,7 @@ error: generic parameters may not be used in const operations LL | foo::<{ Some:: { 0: const { N + 1 } } }>(); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/const-param-in-nested-inline-const-arg.stderr b/tests/ui/const-generics/mgca/const-param-in-nested-inline-const-arg.stderr index fcf13e39e3981..5b0b4087271aa 100644 --- a/tests/ui/const-generics/mgca/const-param-in-nested-inline-const-arg.stderr +++ b/tests/ui/const-generics/mgca/const-param-in-nested-inline-const-arg.stderr @@ -4,7 +4,7 @@ error: generic parameters in const blocks are not allowed; use a named `const` i LL | fn foo(_: S<{ const { const { N } } }>) {} | ^ | - = help: consider factoring the expression into a `type const` item and use it as the const argument instead + = help: consider wrapping the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/double-inline-const.stderr b/tests/ui/const-generics/mgca/double-inline-const.stderr index 846ef73ff7793..139b4301fdf41 100644 --- a/tests/ui/const-generics/mgca/double-inline-const.stderr +++ b/tests/ui/const-generics/mgca/double-inline-const.stderr @@ -9,7 +9,7 @@ note: not a concrete type | LL | impl S { | ^^^^ - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr b/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr index 78663c8cfc855..e1eb839aec40e 100644 --- a/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr +++ b/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr @@ -6,7 +6,7 @@ LL | f::<{ { N } }>(); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr index 89006708b86c8..ea08a8760f70a 100644 --- a/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr +++ b/tests/ui/const-generics/mgca/early-bound-param-lt-bad.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | T: Trait | ^^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index 39747b074550e..28c57d89b556f 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -40,7 +40,7 @@ error: generic parameters may not be used in const operations LL | const ITEM3: usize = gca!(const { N }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:61:31 @@ -48,7 +48,7 @@ error: generic parameters may not be used in const operations LL | T3: Trait, | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:71:58 @@ -56,7 +56,7 @@ error: generic parameters may not be used in const operations LL | struct Default3; | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:30:27 @@ -64,7 +64,7 @@ error: generic parameters may not be used in const operations LL | let _3 = [(); const { N }]; | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:35:26 @@ -72,7 +72,7 @@ error: generic parameters may not be used in const operations LL | let _6: [(); const { N }] = todo!(); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:13:41 @@ -80,7 +80,7 @@ error: generic parameters may not be used in const operations LL | type Adt3 = Foo; | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:21:42 @@ -88,7 +88,7 @@ error: generic parameters may not be used in const operations LL | type Arr3 = [(); const { N }]; | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 13 previous errors diff --git a/tests/ui/const-generics/mgca/gca-macro-feature-gate.stderr b/tests/ui/const-generics/mgca/gca-macro-feature-gate.stderr index 2a9a4cb0fe23c..3bea9a0436111 100644 --- a/tests/ui/const-generics/mgca/gca-macro-feature-gate.stderr +++ b/tests/ui/const-generics/mgca/gca-macro-feature-gate.stderr @@ -16,7 +16,7 @@ LL | fn foo(_: [(); std::gca!(N)]) {} | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: expected expression, found `gca!()` constant --> $DIR/gca-macro-feature-gate.rs:1:32 diff --git a/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr b/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr index 744014bb18ca5..acb7bbd9af0e8 100644 --- a/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr +++ b/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr @@ -10,7 +10,7 @@ error: generic parameters may not be used in const operations LL | f::<{ (N, 1 + 1) }>(); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr index 9b1cc7d43d80a..ae69c356c698c 100644 --- a/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr +++ b/tests/ui/const-generics/mgca/selftyalias-containing-param.stderr @@ -9,7 +9,7 @@ note: not a concrete type | LL | impl S { | ^^^^ - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/selftyparam.stderr b/tests/ui/const-generics/mgca/selftyparam.stderr index 1235009465f89..8b7de91888971 100644 --- a/tests/ui/const-generics/mgca/selftyparam.stderr +++ b/tests/ui/const-generics/mgca/selftyparam.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | fn foo() -> [(); const { let _: Self; 1 }]; | ^^^^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr index 2d725d66fcdc4..526aec3b86b6f 100644 --- a/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr +++ b/tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.stderr @@ -16,7 +16,7 @@ error: generic parameters may not be used in const operations LL | [0; const { size_of::<*mut T>() }]; | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr index e3f6b3b8834b2..74d25d3d5204d 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr @@ -10,7 +10,7 @@ error: generic parameters may not be used in const operations LL | with_point::<{ Point(const { N + 1 }, N) }>(); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr index cdee5ff343ba3..b332f551fabb2 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr @@ -22,7 +22,7 @@ error: generic parameters may not be used in const operations LL | takes_nested_tuple::<{ gca!((N, (N, const { N + 1 }))) }>(); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index 290c2da0007a9..99a51f431562d 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | const FREE1: usize = gca!(const { std::mem::size_of::() }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic-expr.rs:9:51 @@ -12,7 +12,7 @@ error: generic parameters may not be used in const operations LL | const FREE2: usize = gca!(const { I + 1 }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr index a1bb1578afa4c..80dda05bebd49 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | const N1: usize = gca!(const { std::mem::size_of::() }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic_expr-2.rs:20:52 @@ -12,7 +12,7 @@ error: generic parameters may not be used in const operations LL | const N2: usize = gca!(const { I + 1 }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic_expr-2.rs:22:40 @@ -20,7 +20,7 @@ error: generic parameters may not be used in const operations LL | const N3: usize = gca!(const { 2 & X }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/min_const_generics/complex-expression.stderr b/tests/ui/const-generics/min_const_generics/complex-expression.stderr index 2a7d7a35fce9e..93e319bfdcbf6 100644 --- a/tests/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/tests/ui/const-generics/min_const_generics/complex-expression.stderr @@ -6,7 +6,7 @@ LL | struct Break0([u8; { N + 1 }]); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:13:40 @@ -16,7 +16,7 @@ LL | struct Break1([u8; { { N } }]); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:17:17 @@ -26,7 +26,7 @@ LL | let _: [u8; N + 1]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:22:17 @@ -36,7 +36,7 @@ LL | let _ = [0; N + 1]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:26:45 @@ -46,7 +46,7 @@ LL | struct BreakTy0(T, [u8; { size_of::<*mut T>() }]); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:29:47 @@ -56,7 +56,7 @@ LL | struct BreakTy1(T, [u8; { { size_of::<*mut T>() } }]); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:33:32 @@ -66,7 +66,7 @@ LL | let _: [u8; size_of::<*mut T>() + 1]; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro warning: cannot use constants which depend on generic parameters in types --> $DIR/complex-expression.rs:38:17 diff --git a/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr b/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr index 7f203f8afb13b..237374d6e4201 100644 --- a/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr +++ b/tests/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr @@ -6,7 +6,7 @@ LL | test::<{ let _: &'a (); 3 },>(); | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/forbid-non-static-lifetimes.rs:21:16 @@ -16,7 +16,7 @@ LL | [(); (|_: &'a u8| (), 0).1]; | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr b/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr index 87cac5849df89..60799e54016f1 100644 --- a/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr +++ b/tests/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr @@ -10,7 +10,7 @@ note: not a concrete type LL | impl BindsParam for ::Assoc { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 4e3cf9b6d21fe..a43a871694c0d 100644 --- a/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/tests/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -6,7 +6,7 @@ LL | fn t1() -> [u8; std::mem::size_of::()]; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/self-ty-in-const-1.rs:12:41 @@ -20,7 +20,7 @@ note: not a concrete type LL | impl Bar { | ^^^^^^ = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/tests/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr index 8af5a4bd0d388..e6b31a5cba01a 100644 --- a/tests/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr +++ b/tests/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -10,7 +10,7 @@ note: not a concrete type LL | impl Baz for Bar { | ^^^^^^ = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr b/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr index 989378cd313aa..aa23bf25cb383 100644 --- a/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr +++ b/tests/ui/const-generics/outer-lifetime-in-const-generic-default.stderr @@ -6,7 +6,7 @@ LL | let x: &'a (); | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 0c8aac63dd87f..7be9400633958 100644 --- a/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/tests/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -12,7 +12,7 @@ LL | struct Foo()]>(T, U); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0128]: generic parameter defaults cannot reference parameters before they are declared --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:8:21 diff --git a/tests/ui/const-generics/paren.stderr b/tests/ui/const-generics/paren.stderr index d4958cd831424..7bae7629a74e6 100644 --- a/tests/ui/const-generics/paren.stderr +++ b/tests/ui/const-generics/paren.stderr @@ -6,7 +6,7 @@ LL | let _: [u32; (N)] = [5; _]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/paren.rs:14:21 @@ -16,7 +16,7 @@ LL | let _: [u32; { (N) }] = [5; _]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/paren.rs:15:22 @@ -26,7 +26,7 @@ LL | let _: [u32; { { N } }] = [5; _]; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/paren.rs:23:21 @@ -36,7 +36,7 @@ LL | let _: Thing<{ (N) }> = Thing; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/paren.rs:24:22 @@ -46,7 +46,7 @@ LL | let _: Thing<{ { N } }> = Thing; | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0573]: cannot find type `N` in this scope --> $DIR/paren.rs:21:19 diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr index a0dc7043a8966..d55b6358d0779 100644 --- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr +++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr @@ -6,7 +6,7 @@ LL | bar::<{ [1; N] }>(); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/repeat_expr_hack_gives_right_generics.rs:22:19 @@ -16,7 +16,7 @@ LL | bar::<{ [1; { N + 1 }] }>(); | = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/type-relative-path-144547.min.stderr b/tests/ui/const-generics/type-relative-path-144547.min.stderr index 28c1ade6ccce7..cb36dbe4d3027 100644 --- a/tests/ui/const-generics/type-relative-path-144547.min.stderr +++ b/tests/ui/const-generics/type-relative-path-144547.min.stderr @@ -5,7 +5,7 @@ LL | type SupportedArray = [T; ::SUPPORTED_S | ^^^^^^^^^^^^^^ | = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/size-of-t.stderr b/tests/ui/consts/const-eval/size-of-t.stderr index 0265597e4016c..467d6bd4a5d26 100644 --- a/tests/ui/consts/const-eval/size-of-t.stderr +++ b/tests/ui/consts/const-eval/size-of-t.stderr @@ -6,7 +6,7 @@ LL | let _arr: [u8; size_of::()]; | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-gca-const-items.stderr b/tests/ui/feature-gates/feature-gate-gca-const-items.stderr index 2650908e29de8..7b96243e0d2ca 100644 --- a/tests/ui/feature-gates/feature-gate-gca-const-items.stderr +++ b/tests/ui/feature-gates/feature-gate-gca-const-items.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | const INC: usize = gca!(const { N + 1 }); | ^ | - = help: add `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: add `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-gca-macroless-args.stderr b/tests/ui/feature-gates/feature-gate-gca-macroless-args.stderr index 9dbb7108bfb4e..f3079ae808d9c 100644 --- a/tests/ui/feature-gates/feature-gate-gca-macroless-args.stderr +++ b/tests/ui/feature-gates/feature-gate-gca-macroless-args.stderr @@ -6,7 +6,7 @@ LL | fn foo() -> [u8; ::ASSOC] { | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0658]: the `rustc_always_gca` attribute is an experimental feature --> $DIR/feature-gate-gca-macroless-args.rs:2:7 diff --git a/tests/ui/feature-gates/feature-gate-gca-min-const-items.stderr b/tests/ui/feature-gates/feature-gate-gca-min-const-items.stderr index 13f24a86d25ee..37f21afd92987 100644 --- a/tests/ui/feature-gates/feature-gate-gca-min-const-items.stderr +++ b/tests/ui/feature-gates/feature-gate-gca-min-const-items.stderr @@ -16,7 +16,7 @@ LL | fn foo() -> [u8; std::gca!(::ASSOC)] { | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0658]: the `rustc_always_gca` attribute is an experimental feature --> $DIR/feature-gate-gca-min-const-items.rs:2:7 diff --git a/tests/ui/generics/param-in-ct-in-ty-param-default.stderr b/tests/ui/generics/param-in-ct-in-ty-param-default.stderr index 9d9c9102cde5b..87943e7f085d9 100644 --- a/tests/ui/generics/param-in-ct-in-ty-param-default.stderr +++ b/tests/ui/generics/param-in-ct-in-ty-param-default.stderr @@ -6,7 +6,7 @@ LL | struct Foo()]>(T, U); | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr index c78c3e9df86de..f74b04fef8390 100644 --- a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr +++ b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr @@ -6,7 +6,7 @@ LL | beta: [(); foo::<&'a ()>()], | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: lifetime parameter `'s` is never used --> $DIR/issue-64173-unused-lifetimes.rs:3:12 @@ -23,7 +23,7 @@ LL | array: [(); size_of::<&Self>()], | ^^^^ | = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error[E0392]: lifetime parameter `'a` is never used --> $DIR/issue-64173-unused-lifetimes.rs:15:12 diff --git a/tests/ui/resolve/issue-39559.stderr b/tests/ui/resolve/issue-39559.stderr index 6f9fb8377da79..90fdbf43cac5f 100644 --- a/tests/ui/resolve/issue-39559.stderr +++ b/tests/ui/resolve/issue-39559.stderr @@ -6,7 +6,7 @@ LL | entries: [T; D::dim()], | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 1 previous error diff --git a/tests/ui/type/pattern_types/assoc_const.default.stderr b/tests/ui/type/pattern_types/assoc_const.default.stderr index 088495e408f97..8b1184877af83 100644 --- a/tests/ui/type/pattern_types/assoc_const.default.stderr +++ b/tests/ui/type/pattern_types/assoc_const.default.stderr @@ -6,7 +6,7 @@ LL | fn foo(_: pattern_type!(u32 is ::START..=::END) | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/assoc_const.rs:17:61 @@ -16,7 +16,7 @@ LL | fn foo(_: pattern_type!(u32 is ::START..=::END) | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/assoc_const.rs:20:40 @@ -26,7 +26,7 @@ LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: generic parameters may not be used in const operations --> $DIR/assoc_const.rs:20:51 @@ -36,7 +36,7 @@ LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - = help: alternatively, you can use `#![feature(gca_const_items)]` and extract the expression into a `type const` item + = help: alternatively, you can use `#![feature(gca_const_items)]` and wrap the expression in the `gca!` macro error: aborting due to 4 previous errors From 747933f99d5fcadbb16a1bb6d6a8ec9c11a4a4aa Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Sun, 25 Oct 2026 22:57:19 +0000 Subject: [PATCH 09/29] add example for misaligned elements in subslice_range --- library/core/src/slice/mod.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 0677bb8f5871a..7caf8a8046dfd 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -5327,6 +5327,32 @@ impl [T] { /// assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); /// assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); /// ``` + /// Returning `None` with a slice not aligned to the elements of the base array: + /// ``` + /// use core::range::Range; + /// use core::slice::from_ref; + /// + /// let arr: &[[u8; 4]] = &[[0, 1, 2, 3], [4, 5, 6, 7]]; + /// let flattened: &[u8] = arr.as_flattened(); + /// + /// // This sub-slice is aligned with the first element of `arr`: + /// // &[[0, 1, 2, 3], [4, 5, 6, 7]] + /// // &[[0, 1, 2, 3]] + /// let aligned_elem: &[u8; 4] = flattened[0..4].try_into().unwrap(); + /// let aligned_slice: &[[u8; 4]] = from_ref(aligned_elem); + /// + /// // `aligned_slice` is `&arr[0..1]` + /// assert_eq!(arr.subslice_range(aligned_slice), Some(Range { start: 0, end: 1 })); + /// + /// // This sub-slice is **not** aligned to the elements of `arr`, despite pointing inside it: + /// // &[[0, 1, 2, 3], [4, 5, 6, 7]] + /// // &[[1, 2, 3, 4]] + /// let misaligned_elem: &[u8; 4] = flattened[1..5].try_into().unwrap(); + /// let misaligned_slice: &[[u8; 4]] = from_ref(misaligned_elem); + /// + /// // `misaligned_slice` has no corresponding slice of `arr` + /// assert_eq!(arr.subslice_range(misaligned_slice), None); + /// ``` #[must_use] #[stable(feature = "substr_range", since = "1.98.0")] pub fn subslice_range(&self, subslice: &[T]) -> Option> { From 5175ee3f912c741596c920e6023eb5aa186a85b3 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 29 Oct 2026 14:41:46 -0700 Subject: [PATCH 10/29] Tiny optimization to `TypeErrCtxt::report_inference_failure()` In the `br_string` closure, `s` was non-empty if and only if it was created using `format!`; add the extra space directly in that `format!` invocation. --- .../src/error_reporting/infer/region.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index f6205ae5d70f6..a7367e9b39604 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1045,15 +1045,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn report_inference_failure(&self, var_origin: RegionVariableOrigin<'tcx>) -> Diag<'_> { - let br_string = |br: ty::BoundRegionKind<'tcx>| { - let mut s = match br { - ty::BoundRegionKind::Named(def_id) => format!("`{}`", self.tcx.item_name(def_id)), - _ => String::new(), - }; - if !s.is_empty() { - s.push(' '); - } - s + let br_string = |br: ty::BoundRegionKind<'tcx>| match br { + ty::BoundRegionKind::Named(def_id) => format!("`{}` ", self.tcx.item_name(def_id)), + _ => String::new(), }; let var_description = match var_origin { RegionVariableOrigin::Misc(_) => String::new(), From 2a0f69d227200e9d8a0adb862c021c5a457c8125 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 13 Oct 2026 23:39:28 +0200 Subject: [PATCH 11/29] vfe: only use `type.checked.load` on function-pointers The langref says that > The first argument is a pointer from which to load a function pointer So whenever we load something that is not a function pointer, we should not use `type_checked_load` --- compiler/rustc_codegen_ssa/src/meth.rs | 19 +++++++++++---- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 6 +---- compiler/rustc_codegen_ssa/src/size_of_val.rs | 4 ++-- .../codegen/virtual-function-elimination.rs | 24 +++++++++++++++---- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 9c024cacc35c9..c76bd7ad21811 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -57,16 +57,15 @@ impl<'a, 'tcx> VirtualIndex { self, bx: &mut Bx, llvtable: Bx::Value, - ty: Ty<'tcx>, ) -> Bx::Value { // Load the data pointer from the object. - debug!("get_int({:?}, {:?})", llvtable, self); + debug!("get_usize({:?}, {:?})", llvtable, self); let llty = bx.type_isize(); let ptr_size = bx.data_layout().pointer_size(); let vtable_byte_offset = self.0 * ptr_size.bytes(); - load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false) + load_vtable_plain(bx, llvtable, llty, vtable_byte_offset, false) } } @@ -131,8 +130,6 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty: Ty<'tcx>, nonnull: bool, ) -> Bx::Value { - let ptr_align = bx.data_layout().pointer_align().abi; - if bx.cx().sess().opts.unstable_opts.virtual_function_elimination && bx.cx().sess().lto() == Lto::Fat { @@ -145,6 +142,18 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } + load_vtable_plain(bx, llvtable, llty, vtable_byte_offset, nonnull) +} + +fn load_vtable_plain<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + llvtable: Bx::Value, + llty: Bx::Type, + vtable_byte_offset: u64, + nonnull: bool, +) -> Bx::Value { + let ptr_align = bx.data_layout().pointer_align().abi; + let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); let ptr = bx.load(llty, gep, ptr_align); // VTable loads are invariant. diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 5099b9f86c183..44fa4b346b35f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -181,11 +181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN, _ => bug!(), }; - let value = meth::VirtualIndex::from_index(idx).get_usize( - bx, - vtable, - instance.ty(bx.tcx(), bx.typing_env()), - ); + let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable); match name { // Size is always <= isize::MAX. sym::vtable_size => { diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 2467a2354a3dd..2b8427c159ba4 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -29,9 +29,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Load size/align from vtable. let vtable = info.unwrap(); let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE) - .get_usize(bx, vtable, t); + .get_usize(bx, vtable); let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN) - .get_usize(bx, vtable, t); + .get_usize(bx, vtable); // Size is always <= isize::MAX. let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; diff --git a/tests/ui/codegen/virtual-function-elimination.rs b/tests/ui/codegen/virtual-function-elimination.rs index 90fc86f95c5c6..e5dea31df22a7 100644 --- a/tests/ui/codegen/virtual-function-elimination.rs +++ b/tests/ui/codegen/virtual-function-elimination.rs @@ -1,18 +1,34 @@ //@ build-pass -//@ compile-flags: -Zvirtual-function-elimination=true -Clto=true +//@ compile-flags: -Zvirtual-function-elimination=true -Clto=true -Zverify-llvm-ir //@ only-x86_64 //@ no-prefer-dynamic //@ ignore-backends: gcc +#![feature(ptr_metadata)] +#![crate_type = "staticlib"] // issue #123955 -pub fn test0() { +#[no_mangle] +fn test0() { _ = Box::new(()) as Box; } // issue #124092 const X: for<'b> fn(&'b ()) = |&()| (); -pub fn test1() { +#[no_mangle] +fn test1() { let _dyn_debug = Box::new(X) as Box as Box; } -fn main() {} +// issue #164267 +#[no_mangle] +fn test2() { + let x: &dyn std::fmt::Debug = &0u8; + // Reads a non-function-pointer from the vtable. + let _ = std::mem::align_of_val(x); +} + +#[no_mangle] +fn test3() { + let x: &dyn std::fmt::Debug = &0u8; + std::ptr::metadata(x).size_of(); +} From c41febfb737041ded51d97fc4b5bb7f127eabe11 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 13 Oct 2026 23:44:28 +0200 Subject: [PATCH 12/29] vfe: make `load_vtable` private --- compiler/rustc_codegen_ssa/src/base.rs | 8 +++----- compiler/rustc_codegen_ssa/src/meth.rs | 19 ++++++++++++++++++- tests/codegen-llvm/vtable-upcast.rs | 2 +- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index d41e682583e87..e5d790e15f7a4 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -45,7 +45,7 @@ use crate::back::write::{ submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, }; use crate::common::{self, IntPredicate, RealPredicate}; -use crate::meth::load_vtable; +use crate::meth::VirtualIndex; use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; @@ -202,10 +202,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target)); - if let Some(entry_idx) = vptr_entry_idx { - let ptr_size = bx.data_layout().pointer_size(); - let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes(); - load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true) + if let Some(entry_idx) = vptr_entry_idx.map(VirtualIndex::from_index) { + entry_idx.get_data_ptr(bx, old_info, true) } else { old_info } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index c76bd7ad21811..bbf5265eaa07a 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -53,6 +53,23 @@ impl<'a, 'tcx> VirtualIndex { self.get_fn_inner(bx, llvtable, ty, fn_abi, true) } + /// Read a data pointer. For function pointers, use [`VirtualIndex::get_fn`]. + pub(crate) fn get_data_ptr>( + self, + bx: &mut Bx, + llvtable: Bx::Value, + nonnull: bool, + ) -> Bx::Value { + // Load the data pointer from the object. + debug!("get_ptr({:?}, {:?})", llvtable, self); + + let llty = bx.type_ptr(); + let ptr_size = bx.data_layout().pointer_size(); + let vtable_byte_offset = self.0 * ptr_size.bytes(); + + load_vtable_plain(bx, llvtable, llty, vtable_byte_offset, nonnull) + } + pub(crate) fn get_usize>( self, bx: &mut Bx, @@ -122,7 +139,7 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( } /// Call this function whenever you need to load a vtable. -pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( +fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, llvtable: Bx::Value, llty: Bx::Type, diff --git a/tests/codegen-llvm/vtable-upcast.rs b/tests/codegen-llvm/vtable-upcast.rs index d5e74c6e52ca0..2ccb1acd1dd0c 100644 --- a/tests/codegen-llvm/vtable-upcast.rs +++ b/tests/codegen-llvm/vtable-upcast.rs @@ -63,7 +63,7 @@ pub fn upcast_diamond_to_b(x: &dyn Diamond) -> &dyn B { // CHECK: start: // CHECK-NEXT: [[UPCAST_SLOT_PTR:%.+]] = getelementptr inbounds i8, ptr [[VTABLE_PTR]] - // CHECK-NEXT: [[UPCAST_VTABLE_PTR:%.+]] = load ptr, ptr [[UPCAST_SLOT_PTR]] + // CHECK-NEXT: [[UPCAST_VTABLE_PTR:%.+]] = load ptr, ptr [[UPCAST_SLOT_PTR]],{{.*}} !nonnull // CHECK-NEXT: [[FAT_PTR_1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[DATA_PTR]], 0 // CHECK-NEXT: [[FAT_PTR_2:%.+]] = insertvalue { ptr, ptr } [[FAT_PTR_1]], ptr [[UPCAST_VTABLE_PTR]], 1 // CHECK-NEXT: ret { ptr, ptr } [[FAT_PTR_2]] From dfbacfb4f3cdacabd4cf8b00185ae4f84faca6dd Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 13 Oct 2026 23:49:36 +0200 Subject: [PATCH 13/29] vfe: refactor --- compiler/rustc_codegen_ssa/src/meth.rs | 100 ++++++++++--------------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index bbf5265eaa07a..dd0bf6d0a2287 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -15,6 +15,31 @@ impl<'a, 'tcx> VirtualIndex { VirtualIndex(index as u64) } + /// Load this index from the vtable. + fn load_field>( + self, + bx: &mut Bx, + llvtable: Bx::Value, + llty: Bx::Type, + nonnull: bool, + ) -> Bx::Value { + let ptr_size = bx.data_layout().pointer_size(); + let vtable_byte_offset = self.0 * ptr_size.bytes(); + + let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); + let ptr_align = bx.data_layout().pointer_align().abi; + let ptr = bx.load(llty, gep, ptr_align); + + // VTable loads are invariant. + bx.set_invariant_load(ptr); + + if nonnull { + bx.nonnull_metadata(ptr); + } + + ptr + } + fn get_fn_inner>( self, bx: &mut Bx, @@ -30,7 +55,19 @@ impl<'a, 'tcx> VirtualIndex { let ptr_size = bx.data_layout().pointer_size(); let vtable_byte_offset = self.0 * ptr_size.bytes(); - load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull) + if bx.cx().sess().opts.unstable_opts.virtual_function_elimination + && bx.cx().sess().lto() == Lto::Fat + { + if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { + let typeid = typeid_for_trait_ref(bx.tcx(), trait_ref); + let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid.as_bytes()); + return func; + } else if nonnull { + bug!("load nonnull value from a vtable without a principal trait") + } + } + + self.load_field(bx, llvtable, llty, nonnull) } pub(crate) fn get_optional_fn>( @@ -60,14 +97,8 @@ impl<'a, 'tcx> VirtualIndex { llvtable: Bx::Value, nonnull: bool, ) -> Bx::Value { - // Load the data pointer from the object. - debug!("get_ptr({:?}, {:?})", llvtable, self); - - let llty = bx.type_ptr(); - let ptr_size = bx.data_layout().pointer_size(); - let vtable_byte_offset = self.0 * ptr_size.bytes(); - - load_vtable_plain(bx, llvtable, llty, vtable_byte_offset, nonnull) + debug!("get_data_ptr({:?}, {:?})", llvtable, self); + self.load_field(bx, llvtable, bx.type_ptr(), nonnull) } pub(crate) fn get_usize>( @@ -75,14 +106,8 @@ impl<'a, 'tcx> VirtualIndex { bx: &mut Bx, llvtable: Bx::Value, ) -> Bx::Value { - // Load the data pointer from the object. debug!("get_usize({:?}, {:?})", llvtable, self); - - let llty = bx.type_isize(); - let ptr_size = bx.data_layout().pointer_size(); - let vtable_byte_offset = self.0 * ptr_size.bytes(); - - load_vtable_plain(bx, llvtable, llty, vtable_byte_offset, false) + self.load_field(bx, llvtable, bx.type_isize(), false) } } @@ -137,46 +162,3 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } - -/// Call this function whenever you need to load a vtable. -fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - llvtable: Bx::Value, - llty: Bx::Type, - vtable_byte_offset: u64, - ty: Ty<'tcx>, - nonnull: bool, -) -> Bx::Value { - if bx.cx().sess().opts.unstable_opts.virtual_function_elimination - && bx.cx().sess().lto() == Lto::Fat - { - if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { - let typeid = typeid_for_trait_ref(bx.tcx(), trait_ref); - let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid.as_bytes()); - return func; - } else if nonnull { - bug!("load nonnull value from a vtable without a principal trait") - } - } - - load_vtable_plain(bx, llvtable, llty, vtable_byte_offset, nonnull) -} - -fn load_vtable_plain<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - llvtable: Bx::Value, - llty: Bx::Type, - vtable_byte_offset: u64, - nonnull: bool, -) -> Bx::Value { - let ptr_align = bx.data_layout().pointer_align().abi; - - let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr = bx.load(llty, gep, ptr_align); - // VTable loads are invariant. - bx.set_invariant_load(ptr); - if nonnull { - bx.nonnull_metadata(ptr); - } - ptr -} From 2338216e556b4c91771ea75cf04caab1cce02bb3 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 28 Oct 2026 22:29:26 +0000 Subject: [PATCH 14/29] Disallow some special chars in bat script names --- library/std/src/sys/args/windows.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index 4a450a72cdccd..ad7e6f6851b40 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -307,10 +307,12 @@ pub(crate) fn make_bat_command_line( cmd.push(b'"' as u16); // Windows file names cannot contain a `"` character or end with `\\`. // If the script name does then return an error. - if script.contains(&(b'"' as u16)) || script.last() == Some(&(b'\\' as u16)) { + // Also we disallow `^` and `%` to prevent escaping or environment variable substitution. + const INVALID: &[u16] = &[b'"' as u16, b'^' as u16, b'%' as u16]; + if script.iter().any(|c| INVALID.contains(c)) || script.last() == Some(&(b'\\' as u16)) { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Windows file names may not contain `\"` or end with `\\`" + "`Command` rejects batch scripts that contain contain `\"`, `^` or `%` or end with `\\`" )); } cmd.extend_from_slice(script.strip_suffix(&[0]).unwrap_or(script)); From d74cae2adf403de4c2d0f4a65c61227ceeea581d Mon Sep 17 00:00:00 2001 From: Walnut Date: Thu, 29 Oct 2026 23:00:17 -0500 Subject: [PATCH 15/29] limit lldb string summary length --- src/etc/lldb_providers.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 4e0452d4cf77b..a674d5756d1dd 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -380,16 +380,6 @@ def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: return "size=" + str(valobj.GetNumChildren()) -def vec_to_string(vec: SBValue) -> str: - length = vec.GetNumChildren() - chars = [vec.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(length)] - return ( - bytes(chars).decode(errors="replace") - if PY3 - else "".join(chr(char) for char in chars) - ) - - def read_string( process: SBProcess, address: int, length: int, error: Optional[SBError] = None ) -> str: @@ -399,12 +389,31 @@ def read_string( If any error or exception occurs, a placeholder byte array of the form "" will be returned instead.""" + truncated = 0 + # LLDB can sometimes read garbage values for the length of strings due to niche optimization + + # one of several bugs regarding how LLDB handles discriminant values from DWARF debug info. This + # can result in attempted reads in sizes upwards of several thousand petabytes. To help prevent + # the debugger from hard-crashing or eating all the OS's RAM, we defer to LLDB's setting + max_len = ( + process.GetTarget() + .GetDebugger() + .GetSetting("target.max-string-summary-length") + .GetIntegerValue(fail_value=1024) # fall-back to LLDB default + ) + if length > max_len: + truncated = length - max_len + length = max_len + if error is None: error = SBError() try: data = process.ReadMemory(address, length, error) if error.Success(): - return '"' + data.decode("utf-8", "replace") + '"' + output = f"\"{data.decode('utf-8', 'replace')}\"" + if truncated > 0: + output += f" " + + return output else: return f"" except Exception as e: From 516dbc7dd42e68b01b5737fec3de52a76eb3786b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 30 Oct 2026 11:08:25 +0100 Subject: [PATCH 16/29] GCI: Check where-clauses of associated constants for well-formedness --- .../rustc_hir_analysis/src/check/check.rs | 1 - .../rustc_hir_analysis/src/check/wfcheck.rs | 2 ++ .../def-site-predicates-wf.rs | 18 +++++++++++++- .../def-site-predicates-wf.stderr | 24 +++++++++++++++++-- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4f753f02ed9fd..0236247900c5d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -975,7 +975,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ty, tcx.require_lang_item(LangItem::Sized, ty_span), ); - check_where_clauses(wfcx, def_id); wfcheck::check_const_item(wfcx, def_id, ty) })); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0e8a6e323086e..1a63efaa5166b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1342,6 +1342,8 @@ pub(super) fn check_const_item<'tcx>( )); } + check_where_clauses(wfcx, def_id); + res } diff --git a/tests/ui/generic-const-items/def-site-predicates-wf.rs b/tests/ui/generic-const-items/def-site-predicates-wf.rs index 39cdcc304f3e9..bdfdf0c50ea77 100644 --- a/tests/ui/generic-const-items/def-site-predicates-wf.rs +++ b/tests/ui/generic-const-items/def-site-predicates-wf.rs @@ -1,9 +1,25 @@ //! Ensure that we check the predicates for well-formedness at the definition site. #![feature(generic_const_items)] -#![expect(incomplete_features)] + +// NB: Below, we're intentionally not using `$ty:` aka WellFormed($ty) otherwise `$ty` would +// obviously get checked for well-formedness regardless of whether we wfcheck where-clauses or not. const _: () = () where Vec: Sized; //~ ERROR the size for values of type `str` cannot be known at compilation time +trait Trait { + const U: () + where + Vec: Sized; + //~^ ERROR the size for values of type `str` cannot be known at compilation time +} + +impl Trait for () { + const U: () = () + where + Vec: Sized; + //~^ ERROR the size for values of type `str` cannot be known at compilation time +} + fn main() {} diff --git a/tests/ui/generic-const-items/def-site-predicates-wf.stderr b/tests/ui/generic-const-items/def-site-predicates-wf.stderr index 62db089fd5573..84d96becae6bb 100644 --- a/tests/ui/generic-const-items/def-site-predicates-wf.stderr +++ b/tests/ui/generic-const-items/def-site-predicates-wf.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/def-site-predicates-wf.rs:7:15 + --> $DIR/def-site-predicates-wf.rs:9:15 | LL | Vec: Sized; | ^^^^^ doesn't have a size known at compile-time @@ -8,6 +8,26 @@ LL | Vec: Sized; note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error: aborting due to 1 previous error +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/def-site-predicates-wf.rs:21:19 + | +LL | Vec: Sized; + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/def-site-predicates-wf.rs:14:19 + | +LL | Vec: Sized; + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. From 9cf962bcbf40ac0ccbf92a92f6ce1238a3b3341d Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Fri, 30 Oct 2026 09:34:44 -0300 Subject: [PATCH 17/29] Improve delayed bug comment and message --- compiler/rustc_trait_selection/src/traits/vtable.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 71d26a9131618..6dd998791d2dd 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -363,9 +363,13 @@ pub(crate) fn first_method_vtable_slot<'tcx>( let index = prepare_vtable_segments(tcx, source_principal, vtable_segment_callback); if index.is_none() { - // FIXME(lsunsi): investigate if tainting the errors where they happened can ensure we - // don't reach this site at all, or allows us to assert the error happened in the none case. - tcx.dcx().span_delayed_bug(DUMMY_SP, "first method vtable slot = none"); + // This can happen if the trait hierarchy is malformed (e.g., due to + // missing generics on a supertrait bound). There should already be an error + // emitted for this, so we just delay the ICE. + tcx.dcx().delayed_bug(format!( + "could not find the supertrait vtable slot for `{}` -> `{}`", + source, target_principal + )); } index From b828b1dd4f1f42d6557b12daaa24d7927b39787b Mon Sep 17 00:00:00 2001 From: Vara715 <192450883+Vara715@users.noreply.github.com> Date: Fri, 30 Oct 2026 20:15:39 +0530 Subject: [PATCH 18/29] inhabitedness: use try_normalize_erasing_regions on ADT fields Normalizing a field type can fail during const-eval validation if it contains an unsatisfied projection alias. Fall back to a delayed bug instead of panicking with an ICE, and conservatively assume the field is inhabited. --- .../rustc_middle/src/ty/inhabitedness/mod.rs | 7 +++- .../normalize-ice-in-is-opsem-inhabited.rs | 20 +++++++++++ ...normalize-ice-in-is-opsem-inhabited.stderr | 36 +++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/ui/consts/normalize-ice-in-is-opsem-inhabited.rs create mode 100644 tests/ui/consts/normalize-ice-in-is-opsem-inhabited.stderr diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 180a62eaf15a5..07cd0f0018a48 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -375,7 +375,12 @@ impl<'tcx> OpsemInhabitedCtx<'tcx> { let inhabited = adt_def.variants().iter().any(|variant| { variant.fields.iter().all(|field| { let ty = field.ty(tcx, adt_args); - let ty = tcx.normalize_erasing_regions(typing_env, ty); + let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else { + tcx.dcx().delayed_bug(format!( + "failed to normalize field type in `is_opsem_inhabited`: {field:?}" + )); + return true; + }; self.is_inhabited_ty(ty) }) }); diff --git a/tests/ui/consts/normalize-ice-in-is-opsem-inhabited.rs b/tests/ui/consts/normalize-ice-in-is-opsem-inhabited.rs new file mode 100644 index 0000000000000..357704a00b37a --- /dev/null +++ b/tests/ui/consts/normalize-ice-in-is-opsem-inhabited.rs @@ -0,0 +1,20 @@ +trait Tr { + type Out; +} + +impl Tr for fn(X) { + type Out = X; +} + +struct S(&'static S<(T::Out, T::Out)>, std::marker::PhantomData); +//~^ ERROR the trait bound `(::Out, ::Out): Tr` is not satisfied + +const C: &Result, ()> = &Err(()); + +struct S2(&'static (), std::marker::PhantomData<::Out>); +struct A2(&'static S2); +//~^ ERROR the trait bound `T: Tr` is not satisfied + +const C2: &Result, ()> = &Err(()); + +fn main() {} diff --git a/tests/ui/consts/normalize-ice-in-is-opsem-inhabited.stderr b/tests/ui/consts/normalize-ice-in-is-opsem-inhabited.stderr new file mode 100644 index 0000000000000..b36c15789a467 --- /dev/null +++ b/tests/ui/consts/normalize-ice-in-is-opsem-inhabited.stderr @@ -0,0 +1,36 @@ +error[E0277]: the trait bound `(::Out, ::Out): Tr` is not satisfied + --> $DIR/normalize-ice-in-is-opsem-inhabited.rs:9:26 + | +LL | struct S(&'static S<(T::Out, T::Out)>, std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^^ the trait `Tr` is not implemented for `(::Out, ::Out)` + | +help: the trait `Tr` is implemented for fn pointer `fn(X)` + --> $DIR/normalize-ice-in-is-opsem-inhabited.rs:5:1 + | +LL | impl Tr for fn(X) { + | ^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `S` + --> $DIR/normalize-ice-in-is-opsem-inhabited.rs:9:13 + | +LL | struct S(&'static S<(T::Out, T::Out)>, std::marker::PhantomData); + | ^^ required by this bound in `S` + +error[E0277]: the trait bound `T: Tr` is not satisfied + --> $DIR/normalize-ice-in-is-opsem-inhabited.rs:15:23 + | +LL | struct A2(&'static S2); + | ^^^^^ the trait `Tr` is not implemented for `T` + | +note: required by a bound in `S2` + --> $DIR/normalize-ice-in-is-opsem-inhabited.rs:14:14 + | +LL | struct S2(&'static (), std::marker::PhantomData<::Out>); + | ^^ required by this bound in `S2` +help: consider restricting type parameter `T` with trait `Tr` + | +LL | struct A2(&'static S2); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 8b708521afbecdb1b00daa60a0b77383068c41e4 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 30 Oct 2026 16:18:49 +0100 Subject: [PATCH 19/29] Inline usages of `is_doc_keyword_or_attribute` and `is_rustc_doc_primitive` --- compiler/rustc_ast/src/attr/mod.rs | 29 -------------- compiler/rustc_attr_ir/src/attr.rs | 8 ---- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/rustdoc.rs | 39 +++++++++++++++++-- .../passes/collect_intra_doc_links.rs | 4 +- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 4074b56f76da3..8ab79eb4068ea 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -246,29 +246,6 @@ impl AttributeExt for Attribute { } } - fn is_doc_keyword_or_attribute(&self) -> bool { - match &self.kind { - AttrKind::Normal(_) => { - if self.has_name(sym::doc) - && let Some(items) = self.meta_item_list() - { - for item in items { - if item.has_name(sym::keyword) || item.has_name(sym::attribute) { - return true; - } - } - } - } - _ => {} - } - - false - } - - fn is_rustc_doc_primitive(&self) -> bool { - self.has_name(sym::rustc_doc_primitive) - } - /// Returns whether this attribute is any of the proc macro attributes. /// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`. fn is_proc_macro_attr(&self) -> bool { @@ -993,12 +970,6 @@ pub trait AttributeExt: Debug + 'static { /// commented module (for inner doc) vs within its parent module (for outer /// doc). fn doc_resolution_scope(&self) -> Option; - - /// Returns `true` is this attribute contains `doc(keyword)` or `doc(attribute)`. - fn is_doc_keyword_or_attribute(&self) -> bool; - - /// Returns `true` if this is a `#[rustc_doc_primitive]` attribute. - fn is_rustc_doc_primitive(&self) -> bool; } // FIXME(fn_delegation): use function delegation instead of manually forwarding diff --git a/compiler/rustc_attr_ir/src/attr.rs b/compiler/rustc_attr_ir/src/attr.rs index d6f4897edeb05..44fe94fcd44f4 100644 --- a/compiler/rustc_attr_ir/src/attr.rs +++ b/compiler/rustc_attr_ir/src/attr.rs @@ -267,12 +267,4 @@ impl AttributeExt for Attribute { ) ) } - - fn is_doc_keyword_or_attribute(&self) -> bool { - matches!(self, Attribute::Parsed(AttributeKind::Doc(d)) if d.attribute.is_some() || d.keyword.is_some()) - } - - fn is_rustc_doc_primitive(&self) -> bool { - matches!(self, Attribute::Parsed(AttributeKind::RustcDocPrimitive(..))) - } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bffcf60a920ff..746ec7c93459e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -5756,7 +5756,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ResolveDocLinks::Exported if !maybe_exported.eval(self.r) - && !rustdoc::has_primitive_or_keyword_or_attribute_docs(attrs) => + && !rustdoc::has_primitive_or_keyword_or_attribute_docs_ast(attrs) => { return; } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 66bb053299aec..3ff7d5207ac6d 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -11,7 +11,8 @@ use rustc_ast as ast; use rustc_ast::attr::AttributeExt; use rustc_ast::token::DocFragmentKind; use rustc_ast::util::comments::beautify_doc_string; -use rustc_ast::{AttrStyle, join_path_syms}; +use rustc_ast::{AttrKind, AttrStyle, join_path_syms}; +use rustc_attr_ir::{Attribute, AttributeKind, DocAttribute}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; use rustc_middle::ty::TyCtxt; @@ -372,9 +373,41 @@ pub fn strip_generics_from_path(path_str: &str) -> Result, MalformedGen } /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`. -pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -> bool { +pub fn has_primitive_or_keyword_or_attribute_docs_ast(attrs: &[ast::Attribute]) -> bool { for attr in attrs { - if attr.is_rustc_doc_primitive() || attr.is_doc_keyword_or_attribute() { + if attr.has_name(sym::rustc_doc_primitive) { + return true; + } + match &attr.kind { + AttrKind::Normal(_) => { + if attr.has_name(sym::doc) + && let Some(items) = attr.meta_item_list() + { + if items + .iter() + .any(|item| item.has_name(sym::keyword) || item.has_name(sym::attribute)) + { + return true; + } + } + } + _ => {} + } + } + false +} + +/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]` or `#[doc(attribute)]`. +pub fn has_primitive_or_keyword_or_attribute_docs_hir(attrs: &[Attribute]) -> bool { + for attr in attrs { + if matches!( + attr, + Attribute::Parsed( + AttributeKind::RustcDocPrimitive(..) + | AttributeKind::Doc(DocAttribute { attribute: Some(_), .. }) + | AttributeKind::Doc(DocAttribute { keyword: Some(_), .. }) + ) + ) { return true; } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4caaca9c776b2..78e7bcdbd7b01 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -21,7 +21,7 @@ use rustc_middle::ty; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_resolve::rustdoc::pulldown_cmark::LinkType; use rustc_resolve::rustdoc::{ - DocStrings, MalformedGenerics, has_primitive_or_keyword_or_attribute_docs, + DocStrings, MalformedGenerics, has_primitive_or_keyword_or_attribute_docs_hir, prepare_to_doc_link_resolution, source_span_for_markdown_range, strip_generics_from_path, }; use rustc_span::def_id::ModId; @@ -1081,7 +1081,7 @@ impl LinkCollector<'_, '_> { && item_id .as_local() .is_some_and(|local_def_id| !effective_visibilities.is_exported(local_def_id)) - && !has_primitive_or_keyword_or_attribute_docs(&item.attrs.other_attrs) + && !has_primitive_or_keyword_or_attribute_docs_hir(&item.attrs.other_attrs) }; if let Some(def_id) = item.item_id.as_def_id() From 67631026539ae3103f08a9e2e1d04a4df79b167e Mon Sep 17 00:00:00 2001 From: Abhinav Srivastav Date: Sat, 31 Oct 2026 00:02:37 +0530 Subject: [PATCH 20/29] tests: clarify dead_code_pub_in_binary FIXME after Cargo workaround --- tests/ui/lint/dead-code-pub-in-binary/library-test.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ui/lint/dead-code-pub-in-binary/library-test.rs b/tests/ui/lint/dead-code-pub-in-binary/library-test.rs index 3a4383c4b979a..afcc81d1c9503 100644 --- a/tests/ui/lint/dead-code-pub-in-binary/library-test.rs +++ b/tests/ui/lint/dead-code-pub-in-binary/library-test.rs @@ -4,6 +4,7 @@ #![expect(dead_code_pub_in_binary)] #![deny(unfulfilled_lint_expectations)] -// FIXME(#159078): `--test` causes the library crate to be treated as an -// executable, fulfilling this lint expectation incorrectly. +// FIXME(#159078): `--test` causes rustc to treat this library as an +// executable, incorrectly fulfilling the lint expectation. Cargo works +// around this for library test units (rust-lang/cargo#17608). pub fn unused_pub_fn() {} From 4bc1baacf2ef5538b86b89bcd08302c3f928d252 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Mon, 11 Mar 2024 00:00:41 -0400 Subject: [PATCH 21/29] use [N x i8] for array index / ptr offset GEP types This avoids depending on LLVM's struct types to determine the size of the array/pointer element. Co-Authored-By: Bee --- compiler/rustc_codegen_gcc/src/builder.rs | 53 +++-------- .../rustc_codegen_gcc/src/intrinsic/simd.rs | 5 +- compiler/rustc_codegen_llvm/src/builder.rs | 89 ++++++++----------- .../src/builder/gpu_offload.rs | 18 ++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/place.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 5 +- .../rustc_codegen_ssa/src/traits/builder.rs | 21 ++--- tests/codegen-llvm/intrinsics/offset.rs | 4 +- tests/codegen-llvm/ptr-arithmetic.rs | 6 +- tests/codegen-llvm/simd/simd_arith_offset.rs | 11 ++- tests/codegen-llvm/slice-iter-nonnull.rs | 4 +- 13 files changed, 93 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 3fad1dfa8b8d9..e0d2c83effb14 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -17,8 +17,8 @@ use rustc_codegen_ssa::common::{ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ - BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, - LayoutTypeCodegenMethods, OverflowOp, ReturnSlot, StaticBuilderMethods, + BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, OverflowOp, + ReturnSlot, StaticBuilderMethods, }; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -1184,11 +1184,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let align = dest.val.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); cg_elem.val.store(self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); - let next = self.inbounds_gep( - self.backend_type(cg_elem.layout), - current.to_rvalue(), - &[self.const_usize(1)], - ); + let next = self + .inbounds_ptradd(current.to_rvalue(), self.const_usize(cg_elem.layout.size.bytes())); + let next = self.context.new_cast(self.location, next, ptr_type); self.llbb().add_assignment(self.location, current, next); self.br(header_bb); @@ -1267,52 +1265,29 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ); } - fn gep( - &mut self, - typ: Type<'gcc>, - ptr: RValue<'gcc>, - indices: &[RValue<'gcc>], - ) -> RValue<'gcc> { - // NOTE: due to opaque pointers now being used, we need to cast here. - let ptr = self.context.new_cast(self.location, ptr, typ.make_pointer()); + fn gep(&mut self, stride: Size, ptr: RValue<'gcc>, index: RValue<'gcc>) -> RValue<'gcc> { let ptr_type = ptr.get_type(); - let mut pointee_type = ptr.get_type(); // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is // always considered in bounds in GCC (FIXME(antoyo): to be verified). // So, we have to cast to a number. - let mut result = self.context.new_bitcast(self.location, ptr, self.sizet_type); - // FIXME(antoyo): if there were more than 1 index, this code is probably wrong and would - // require dereferencing the pointer. - for index in indices { - pointee_type = pointee_type.get_pointee().expect("pointee type"); - #[cfg(feature = "master")] - let pointee_size = { - let size = self.cx.context.new_sizeof(pointee_type); - self.context.new_cast(self.location, size, index.get_type()) - }; - #[cfg(not(feature = "master"))] - let pointee_size = - self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); - result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type); - } + let ptr = self.context.new_bitcast(self.location, ptr, self.sizet_type); + let pointee_size = + self.context.new_rvalue_from_int(index.get_type(), stride.bytes() as i32); + let result = ptr + self.gcc_int_cast(index * pointee_size, self.sizet_type); self.context.new_bitcast(self.location, result, ptr_type) } fn inbounds_gep( &mut self, - typ: Type<'gcc>, + stride: Size, ptr: RValue<'gcc>, - indices: &[RValue<'gcc>], + index: RValue<'gcc>, ) -> RValue<'gcc> { + let typ = self.cx.type_array(self.cx.type_i8(), stride.bytes()); // NOTE: due to opaque pointers now being used, we need to cast here. let ptr = self.context.new_cast(self.location, ptr, typ.make_pointer()); // NOTE: array indexing is always considered in bounds in GCC (FIXME(antoyo): to be verified). - let mut indices = indices.iter(); - let index = indices.next().expect("first index in inbounds_gep"); - let mut result = self.context.new_array_access(self.location, ptr, *index); - for index in indices { - result = self.context.new_array_access(self.location, result, *index); - } + let result = self.context.new_array_access(self.location, ptr, index); result.get_address(self.location) } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 5b782d5776129..a46015d0bae4a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -11,7 +11,7 @@ use rustc_codegen_ssa::diagnostics::ExpectedPointerMutability; use rustc_codegen_ssa::diagnostics::InvalidMonomorphization; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, LayoutTypeCodegenMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; #[cfg(feature = "master")] use rustc_hir as hir; use rustc_middle::mir::BinOp; @@ -671,7 +671,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( ); } - let pointee_type = bx.backend_type(layout); let pointers = args[0].immediate(); let offsets = args[1].immediate(); let elem_type = llret_ty.dyncast_vector().expect("vector return type").get_element_type(); @@ -680,7 +679,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let index = bx.context.new_rvalue_from_long(bx.usize_type, i as _); let pointer = bx.extract_element(pointers, index); let offset = bx.extract_element(offsets, index); - let pointer = bx.gep(pointee_type, pointer, &[offset]); + let pointer = bx.gep(layout.size, pointer, offset); // GCC has no pointer vectors, so the lanes are `usize`. bx.ptrtoint(pointer, elem_type) }) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 930463d251d7d..4d2f92f0d818d 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -160,7 +160,9 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { val } - pub(crate) fn inbounds_gep( + /// Don't use this method: instead use `inbounds_gep` or `inbounds_ptradd`. + // FIXME: Remove once unused. + pub(crate) fn typed_inbounds_gep( &mut self, ty: &'ll Type, ptr: &'ll Value, @@ -179,6 +181,33 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { } } + fn build_gep( + &mut self, + stride: Size, + ptr: &'ll Value, + index: &'ll Value, + flags: GEPNoWrapFlags, + ) -> &'ll Value { + let ty = if stride.bytes() == 1 { + // LLVM prefers `i8` as the canonical form for a single-byte GEP. + self.cx.type_i8() + } else { + self.cx.type_array(self.cx.type_i8(), stride.bytes()) + }; + let indices = &[index]; + unsafe { + llvm::LLVMBuildGEPWithNoWrapFlags( + self.llbuilder(), + ty, + ptr, + indices.as_ptr(), + indices.len() as c_uint, + UNNAMED, + flags, + ) + } + } + pub(crate) fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { debug!("Store {:?} -> {:?}", val, ptr); assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer); @@ -963,56 +992,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } - fn gep(&mut self, ty: &'ll Type, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value { - unsafe { - llvm::LLVMBuildGEPWithNoWrapFlags( - self.llbuilder(), - ty, - ptr, - indices.as_ptr(), - indices.len() as c_uint, - UNNAMED, - GEPNoWrapFlags::default(), - ) - } + fn gep(&mut self, stride: Size, ptr: &'ll Value, index: &'ll Value) -> &'ll Value { + self.build_gep(stride, ptr, index, GEPNoWrapFlags::default()) } - fn inbounds_gep( - &mut self, - ty: &'ll Type, - ptr: &'ll Value, - indices: &[&'ll Value], - ) -> &'ll Value { - unsafe { - llvm::LLVMBuildGEPWithNoWrapFlags( - self.llbuilder(), - ty, - ptr, - indices.as_ptr(), - indices.len() as c_uint, - UNNAMED, - GEPNoWrapFlags::InBounds, - ) - } + fn inbounds_gep(&mut self, stride: Size, ptr: &'ll Value, index: &'ll Value) -> &'ll Value { + self.build_gep(stride, ptr, index, GEPNoWrapFlags::InBounds) } - fn inbounds_nuw_gep( - &mut self, - ty: &'ll Type, - ptr: &'ll Value, - indices: &[&'ll Value], - ) -> &'ll Value { - unsafe { - llvm::LLVMBuildGEPWithNoWrapFlags( - self.llbuilder(), - ty, - ptr, - indices.as_ptr(), - indices.len() as c_uint, - UNNAMED, - GEPNoWrapFlags::InBounds | GEPNoWrapFlags::NUW, - ) - } + fn inbounds_nuw_gep(&mut self, stride: Size, ptr: &'ll Value, index: &'ll Value) -> &'ll Value { + self.build_gep(stride, ptr, index, GEPNoWrapFlags::InBounds | GEPNoWrapFlags::NUW) } /* Casts */ @@ -1729,11 +1718,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { .val .store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align)); - let next = body_bx.inbounds_gep( - self.backend_type(cg_elem.layout), - current, - &[self.const_usize(1)], - ); + let next = body_bx.inbounds_ptradd(current, self.const_usize(cg_elem.layout.size.bytes())); body_bx.br(header_bb); header_bx.add_incoming_to_phi(current, next, body_bb); diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index de7b4688f1471..4b688d3e03da6 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -627,7 +627,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( other => bug!("offload does not support {other:?}"), }; - let gep = builder.inbounds_gep(cx.type_f32(), gep_base, &[i32_0]); + let gep = builder.typed_inbounds_gep(cx.type_f32(), gep_base, &[i32_0]); vals.push(base_val); geps.push(gep); @@ -635,13 +635,13 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( for i in 0..num_args { let idx = cx.get_const_i32(i); - let gep1 = builder.inbounds_gep(ty, a1, &[i32_0, idx]); + let gep1 = builder.typed_inbounds_gep(ty, a1, &[i32_0, idx]); builder.store(vals[i as usize], gep1, Align::EIGHT); - let gep2 = builder.inbounds_gep(ty, a2, &[i32_0, idx]); + let gep2 = builder.typed_inbounds_gep(ty, a2, &[i32_0, idx]); builder.store(geps[i as usize], gep2, Align::EIGHT); if !matches!(metadata[i as usize].payload_size, OffloadSize::Static(_)) { - let gep3 = builder.inbounds_gep(ty2, a4, &[i32_0, idx]); + let gep3 = builder.typed_inbounds_gep(ty2, a4, &[i32_0, idx]); let size_val = get_runtime_size(builder, args, i as usize, &metadata[i as usize]); builder.store(size_val, gep3, Align::EIGHT); } @@ -661,9 +661,10 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let cx = builder.cx; let i32_0 = cx.get_const_i32(0); - let gep1 = builder.inbounds_gep(ty, a1, &[i32_0, i32_0]); - let gep2 = builder.inbounds_gep(ty, a2, &[i32_0, i32_0]); - let gep3 = if is_dynamic { builder.inbounds_gep(ty2, a4, &[i32_0, i32_0]) } else { a4 }; + let gep1 = builder.typed_inbounds_gep(ty, a1, &[i32_0, i32_0]); + let gep2 = builder.typed_inbounds_gep(ty, a2, &[i32_0, i32_0]); + let gep3 = + if is_dynamic { builder.typed_inbounds_gep(ty2, a4, &[i32_0, i32_0]) } else { a4 }; [gep1, gep2, gep3] } @@ -710,7 +711,8 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( // Step 3) // Here we fill the KernelArgsTy, see the documentation above for (i, value) in values.iter().enumerate() { - let ptr = builder.inbounds_gep(tgt_kernel_decl, a5, &[i32_0, cx.get_const_i32(i as u64)]); + let ptr = + builder.typed_inbounds_gep(tgt_kernel_decl, a5, &[i32_0, cx.get_const_i32(i as u64)]); let name = std::ffi::CString::new(value.1).unwrap(); llvm::set_value_name(ptr, &name.as_bytes()); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 12319407b456e..92ff53af84703 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -3397,7 +3397,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } let offsets = args[1].immediate(); - return Ok(bx.gep(bx.backend_type(layout), ptrs, &[offsets])); + return Ok(bx.gep(layout.size, ptrs, offsets)); } if name == sym::simd_saturating_add || name == sym::simd_saturating_sub { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 5099b9f86c183..7ed3066c1dbc0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); let ptr = args[0].immediate(); let offset = args[1].immediate(); - OperandValue::Immediate(bx.gep(bx.backend_type(layout), ptr, &[offset])) + OperandValue::Immediate(bx.gep(layout.size, ptr, offset)) } sym::copy => { copy_intrinsic( diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 6c6d20568a9f9..ce166fbe59fd9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout.size }; - let llval = bx.inbounds_nuw_gep(bx.cx().backend_type(layout), self.val.llval, &[llindex]); + let llval = bx.inbounds_nuw_gep(layout.size, self.val.llval, llindex); let align = self.val.align.restrict_for_offset(offset); PlaceValue::new_sized(llval, align).with_type(layout) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 622d205d68268..bfd0beb8cea38 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -970,11 +970,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // so offsetting a pointer to ZST is a noop. lhs } else { - let llty = bx.cx().backend_type(pointee_layout); if !rhs_ty.is_signed() { - bx.inbounds_nuw_gep(llty, lhs, &[rhs]) + bx.inbounds_nuw_gep(pointee_layout.size, lhs, rhs) } else { - bx.inbounds_gep(llty, lhs, &[rhs]) + bx.inbounds_gep(pointee_layout.size, lhs, rhs) } } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 203274ccbb9fb..281549d252bb1 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -350,26 +350,23 @@ pub trait BuilderMethods<'a, 'tcx>: size: Size, ); - fn gep(&mut self, ty: Self::Type, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value; - fn inbounds_gep( - &mut self, - ty: Self::Type, - ptr: Self::Value, - indices: &[Self::Value], - ) -> Self::Value; + fn gep(&mut self, stride: Size, ptr: Self::Value, index: Self::Value) -> Self::Value; + fn inbounds_gep(&mut self, stride: Size, ptr: Self::Value, index: Self::Value) -> Self::Value { + self.gep(stride, ptr, index) + } fn inbounds_nuw_gep( &mut self, - ty: Self::Type, + stride: Size, ptr: Self::Value, - indices: &[Self::Value], + index: Self::Value, ) -> Self::Value { - self.inbounds_gep(ty, ptr, indices) + self.inbounds_gep(stride, ptr, index) } fn ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value { - self.gep(self.cx().type_i8(), ptr, &[offset]) + self.gep(Size::from_bytes(1), ptr, offset) } fn inbounds_ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value { - self.inbounds_gep(self.cx().type_i8(), ptr, &[offset]) + self.inbounds_gep(Size::from_bytes(1), ptr, offset) } fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; diff --git a/tests/codegen-llvm/intrinsics/offset.rs b/tests/codegen-llvm/intrinsics/offset.rs index cf0c7c7ac7d74..d713970630d51 100644 --- a/tests/codegen-llvm/intrinsics/offset.rs +++ b/tests/codegen-llvm/intrinsics/offset.rs @@ -18,7 +18,7 @@ pub unsafe fn offset_zst(p: *const (), d: usize) -> *const () { // CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d) #[no_mangle] pub unsafe fn offset_isize(p: *const u32, d: isize) -> *const u32 { - // CHECK: %[[R:.*]] = getelementptr inbounds i32, ptr %p, [[SIZE]] %d + // CHECK: %[[R:.*]] = getelementptr inbounds [4 x i8], ptr %p, [[SIZE]] %d // CHECK-NEXT: ret ptr %[[R]] offset(p, d) } @@ -27,7 +27,7 @@ pub unsafe fn offset_isize(p: *const u32, d: isize) -> *const u32 { // CHECK-SAME: (ptr noundef %p, [[SIZE]] noundef %d) #[no_mangle] pub unsafe fn offset_usize(p: *const u64, d: usize) -> *const u64 { - // CHECK: %[[R:.*]] = getelementptr inbounds{{( nuw)?}} i64, ptr %p, [[SIZE]] %d + // CHECK: %[[R:.*]] = getelementptr inbounds{{( nuw)?}} [8 x i8], ptr %p, [[SIZE]] %d // CHECK-NEXT: ret ptr %[[R]] offset(p, d) } diff --git a/tests/codegen-llvm/ptr-arithmetic.rs b/tests/codegen-llvm/ptr-arithmetic.rs index c0ae28ca70ad5..ea93366550982 100644 --- a/tests/codegen-llvm/ptr-arithmetic.rs +++ b/tests/codegen-llvm/ptr-arithmetic.rs @@ -6,7 +6,7 @@ // CHECK-SAME: [[WORD:i[0-9]+]] noundef %n) #[no_mangle] pub unsafe fn i32_add(p: *const i32, n: usize) -> *const i32 { - // CHECK: %[[TEMP:.+]] = getelementptr inbounds{{( nuw)?}} {{i32|\[4 x i8\]}}, ptr %p, [[WORD]] %n + // CHECK: %[[TEMP:.+]] = getelementptr inbounds{{( nuw)?}} [4 x i8], ptr %p, [[WORD]] %n // CHECK: ret ptr %[[TEMP]] p.add(n) } @@ -18,7 +18,7 @@ pub unsafe fn i32_add(p: *const i32, n: usize) -> *const i32 { #[no_mangle] pub unsafe fn i32_sub(p: *const i32, n: usize) -> *const i32 { // CHECK: %[[DELTA:.+]] = sub nsw [[WORD]] 0, %n - // CHECK: %[[TEMP:.+]] = getelementptr inbounds {{i32|\[4 x i8\]}}, ptr %p, [[WORD]] %[[DELTA]] + // CHECK: %[[TEMP:.+]] = getelementptr inbounds [4 x i8], ptr %p, [[WORD]] %[[DELTA]] // CHECK: ret ptr %[[TEMP]] p.sub(n) } @@ -27,7 +27,7 @@ pub unsafe fn i32_sub(p: *const i32, n: usize) -> *const i32 { // CHECK-SAME: [[WORD:i[0-9]+]] noundef %d) #[no_mangle] pub unsafe fn i32_offset(p: *const i32, d: isize) -> *const i32 { - // CHECK: %[[TEMP:.+]] = getelementptr inbounds {{i32|\[4 x i8\]}}, ptr %p, [[WORD]] %d + // CHECK: %[[TEMP:.+]] = getelementptr inbounds [4 x i8], ptr %p, [[WORD]] %d // CHECK: ret ptr %[[TEMP]] p.offset(d) } diff --git a/tests/codegen-llvm/simd/simd_arith_offset.rs b/tests/codegen-llvm/simd/simd_arith_offset.rs index 210b4e9bb50e1..0de68c4a2eac8 100644 --- a/tests/codegen-llvm/simd/simd_arith_offset.rs +++ b/tests/codegen-llvm/simd/simd_arith_offset.rs @@ -14,9 +14,16 @@ use minisimd::*; /// A vector of *const T. pub type SimdConstPtr = Simd<*const T, LANES>; -// CHECK-LABEL: smoke +// CHECK-LABEL: u8_offset #[no_mangle] -pub fn smoke(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { +pub fn u8_offset(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { // CHECK: getelementptr i8, <8 x ptr> %0, <8 x i64> %1 unsafe { simd_arith_offset(ptrs, offsets) } } + +// CHECK-LABEL: u64_offset +#[no_mangle] +pub fn u64_offset(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { + // CHECK: getelementptr [8 x i8], <8 x ptr> %0, <8 x i64> %1 + unsafe { simd_arith_offset(ptrs, offsets) } +} diff --git a/tests/codegen-llvm/slice-iter-nonnull.rs b/tests/codegen-llvm/slice-iter-nonnull.rs index 8ef313f2d6715..8f74a3c352de9 100644 --- a/tests/codegen-llvm/slice-iter-nonnull.rs +++ b/tests/codegen-llvm/slice-iter-nonnull.rs @@ -55,7 +55,7 @@ pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&' #[no_mangle] pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { // CHECK-NOT: slice - // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} {{i32|\[4 x i8\]}}{{.+}} %slice.0{{.+}} %slice.1 + // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} [4 x i8]{{.+}} %slice.0{{.+}} %slice.1 // CHECK-NOT: slice // CHECK: insertvalue {{.+}} ptr %slice.0, 0 // CHECK-NOT: slice @@ -70,7 +70,7 @@ pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { #[no_mangle] pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> { // CHECK-NOT: slice - // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} {{i32|\[4 x i8\]}}{{.+}} %slice.0{{.+}} %slice.1 + // CHECK: %[[END:.+]] = getelementptr inbounds{{( nuw)?}} [4 x i8]{{.+}} %slice.0{{.+}} %slice.1 // CHECK-NOT: slice // CHECK: insertvalue {{.+}} ptr %slice.0, 0 // CHECK-NOT: slice From 36265cfe8f93881b73dd463e6f6c7f2354d4001f Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 30 Oct 2026 15:30:33 -0500 Subject: [PATCH 22/29] Add tests for 165052 ICE --- tests/crashes/165052-1.rs | 12 ++++++++++++ tests/crashes/165052-2.rs | 13 +++++++++++++ tests/crashes/165052-3.rs | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/crashes/165052-1.rs create mode 100644 tests/crashes/165052-2.rs create mode 100644 tests/crashes/165052-3.rs diff --git a/tests/crashes/165052-1.rs b/tests/crashes/165052-1.rs new file mode 100644 index 0000000000000..01ef7b421ab5a --- /dev/null +++ b/tests/crashes/165052-1.rs @@ -0,0 +1,12 @@ +//@ known-bug: #165052 + +struct S<'a> { + //~^ ERROR lifetime parameter `'a` is never used + n: &'static u8, // changing 'static to 'a makes it compile +} +fn b(n: &u8) -> S { + S { n } + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/crashes/165052-2.rs b/tests/crashes/165052-2.rs new file mode 100644 index 0000000000000..1a1a9ee837365 --- /dev/null +++ b/tests/crashes/165052-2.rs @@ -0,0 +1,13 @@ +//@ known-bug: #165052 + +enum Ast<'a> { + Add(&'a Ast<'static>, &'a Ast<'a>), +} +fn mk_add_bad1<'a, 'b>(x: &'a Ast, y: &'b Ast) -> Ast<'a> { + Ast::Add(x, y) + //~^ ERROR explicit lifetime required in the type of `y` + //~| ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/crashes/165052-3.rs b/tests/crashes/165052-3.rs new file mode 100644 index 0000000000000..2dfb13c0a2f00 --- /dev/null +++ b/tests/crashes/165052-3.rs @@ -0,0 +1,18 @@ +//@ known-bug: #165052 + +struct S<'a> { + m: &'a dyn std::fmt::Debug, + n: &'static u8, +} +fn b<'a>( + m: &'a dyn std::fmt::Debug, + n: &'a u8, +) -> S<'a> { + S { + m, + n, + //~^ ERROR lifetime may not live long enough + } +} + +fn main() {} From 5ae49d9f6d5327697315a984bae6e92b9e5eae74 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 30 Oct 2026 15:26:05 -0500 Subject: [PATCH 23/29] Don't ICE when making diagnostic in `point_at_dyn_trait_in_field_def` if there's no `dyn Trait` field to point at --- .../src/diagnostics/region_errors.rs | 6 +++ ...c-obligation-field-with-other-errors-1.rs} | 5 ++- ...bligation-field-with-other-errors-1.stderr | 19 +++++++++ ...c-obligation-field-with-other-errors-2.rs} | 4 +- ...bligation-field-with-other-errors-2.stderr | 40 +++++++++++++++++++ ...c-obligation-field-with-other-errors-3.rs} | 4 +- ...bligation-field-with-other-errors-3.stderr | 11 +++++ 7 files changed, 85 insertions(+), 4 deletions(-) rename tests/{crashes/165052-1.rs => ui/lifetimes/static-obligation-field-with-other-errors-1.rs} (77%) create mode 100644 tests/ui/lifetimes/static-obligation-field-with-other-errors-1.stderr rename tests/{crashes/165052-2.rs => ui/lifetimes/static-obligation-field-with-other-errors-2.rs} (82%) create mode 100644 tests/ui/lifetimes/static-obligation-field-with-other-errors-2.stderr rename tests/{crashes/165052-3.rs => ui/lifetimes/static-obligation-field-with-other-errors-3.rs} (78%) create mode 100644 tests/ui/lifetimes/static-obligation-field-with-other-errors-3.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 9bb60d47ac849..35815bc91645e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1109,6 +1109,12 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { let mut v = ty::TraitObjectVisitor(vec![]); v.visit_ty_unambig(f.ty); + + if v.0.is_empty() { + // No trait object found in this return + continue; + } + let mut span: MultiSpan = v.0.iter().map(|x| x.span).collect::>().into(); // Display the item and variant lines. for def_span in def_spans { diff --git a/tests/crashes/165052-1.rs b/tests/ui/lifetimes/static-obligation-field-with-other-errors-1.rs similarity index 77% rename from tests/crashes/165052-1.rs rename to tests/ui/lifetimes/static-obligation-field-with-other-errors-1.rs index 01ef7b421ab5a..bb96a65f85014 100644 --- a/tests/crashes/165052-1.rs +++ b/tests/ui/lifetimes/static-obligation-field-with-other-errors-1.rs @@ -1,5 +1,6 @@ -//@ known-bug: #165052 - +// Regression test for #165052 +// This used to ICE +//@ check-fail struct S<'a> { //~^ ERROR lifetime parameter `'a` is never used n: &'static u8, // changing 'static to 'a makes it compile diff --git a/tests/ui/lifetimes/static-obligation-field-with-other-errors-1.stderr b/tests/ui/lifetimes/static-obligation-field-with-other-errors-1.stderr new file mode 100644 index 0000000000000..fe1fb3ed2ef3a --- /dev/null +++ b/tests/ui/lifetimes/static-obligation-field-with-other-errors-1.stderr @@ -0,0 +1,19 @@ +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/static-obligation-field-with-other-errors-1.rs:4:10 + | +LL | struct S<'a> { + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: lifetime may not live long enough + --> $DIR/static-obligation-field-with-other-errors-1.rs:9:9 + | +LL | fn b(n: &u8) -> S { + | - let's call the lifetime of this reference `'1` +LL | S { n } + | ^ this usage requires that `'1` must outlive `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/crashes/165052-2.rs b/tests/ui/lifetimes/static-obligation-field-with-other-errors-2.rs similarity index 82% rename from tests/crashes/165052-2.rs rename to tests/ui/lifetimes/static-obligation-field-with-other-errors-2.rs index 1a1a9ee837365..500775b7d14ef 100644 --- a/tests/crashes/165052-2.rs +++ b/tests/ui/lifetimes/static-obligation-field-with-other-errors-2.rs @@ -1,4 +1,6 @@ -//@ known-bug: #165052 +// Regression test for #165052 +// This used to ICE +//@ check-fail enum Ast<'a> { Add(&'a Ast<'static>, &'a Ast<'a>), diff --git a/tests/ui/lifetimes/static-obligation-field-with-other-errors-2.stderr b/tests/ui/lifetimes/static-obligation-field-with-other-errors-2.stderr new file mode 100644 index 0000000000000..dfaa5475ee07d --- /dev/null +++ b/tests/ui/lifetimes/static-obligation-field-with-other-errors-2.stderr @@ -0,0 +1,40 @@ +error: lifetime may not live long enough + --> $DIR/static-obligation-field-with-other-errors-2.rs:9:5 + | +LL | fn mk_add_bad1<'a, 'b>(x: &'a Ast, y: &'b Ast) -> Ast<'a> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | Ast::Add(x, y) + | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` +help: consider reusing a named lifetime parameter + | +LL | fn mk_add_bad1<'a, 'b>(x: &'a Ast<'a>, y: &'b Ast<'a>) -> Ast<'a> { + | ++++ ++++ + +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/static-obligation-field-with-other-errors-2.rs:9:5 + | +LL | Ast::Add(x, y) + | ^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn mk_add_bad1<'a, 'b>(x: &'a Ast, y: &'b Ast<'a>) -> Ast<'a> { + | ++++ + +error: lifetime may not live long enough + --> $DIR/static-obligation-field-with-other-errors-2.rs:9:14 + | +LL | fn mk_add_bad1<'a, 'b>(x: &'a Ast, y: &'b Ast) -> Ast<'a> { + | - --- lifetime `'1` introduced here + | | + | has type `&Ast<'1>` +LL | Ast::Add(x, y) + | ^ this usage requires that `'1` must outlive `'static` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/tests/crashes/165052-3.rs b/tests/ui/lifetimes/static-obligation-field-with-other-errors-3.rs similarity index 78% rename from tests/crashes/165052-3.rs rename to tests/ui/lifetimes/static-obligation-field-with-other-errors-3.rs index 2dfb13c0a2f00..6dfcbdbe68fe0 100644 --- a/tests/crashes/165052-3.rs +++ b/tests/ui/lifetimes/static-obligation-field-with-other-errors-3.rs @@ -1,4 +1,6 @@ -//@ known-bug: #165052 +// Regression test for #165052 +// This used to ICE +//@ check-fail struct S<'a> { m: &'a dyn std::fmt::Debug, diff --git a/tests/ui/lifetimes/static-obligation-field-with-other-errors-3.stderr b/tests/ui/lifetimes/static-obligation-field-with-other-errors-3.stderr new file mode 100644 index 0000000000000..fbcb0383b90d0 --- /dev/null +++ b/tests/ui/lifetimes/static-obligation-field-with-other-errors-3.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/static-obligation-field-with-other-errors-3.rs:15:9 + | +LL | fn b<'a>( + | -- lifetime `'a` defined here +... +LL | n, + | ^ this usage requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + From 4f492503e9a5d43ebadb5d62d50632358560a35f Mon Sep 17 00:00:00 2001 From: malezjaa Date: Sat, 31 Oct 2026 01:01:31 +0100 Subject: [PATCH 24/29] add MaybeUninit::from_ref --- library/core/src/mem/maybe_uninit.rs | 47 ++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 94703940baa1f..98afd345eec28 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1,6 +1,6 @@ use crate::any::type_name; use crate::clone::TrivialClone; -use crate::marker::Destruct; +use crate::marker::{Destruct, Freeze}; use crate::mem::{ManuallyDrop, transmute_neo}; use crate::{fmt, intrinsics, ptr, slice}; @@ -1062,6 +1062,9 @@ impl MaybeUninit { /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still /// contain padding bytes which are left uninitialized. /// + /// This method requires `T: Freeze`. It's not available for types with interior mutability, + /// such as `Cell`. + /// /// # Examples /// /// ``` @@ -1075,7 +1078,10 @@ impl MaybeUninit { /// assert_eq!(bytes, val.to_ne_bytes()); /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - pub const fn as_bytes(&self) -> &[MaybeUninit] { + pub const fn as_bytes(&self) -> &[MaybeUninit] + where + T: Freeze, + { // SAFETY: MaybeUninit is always valid, even for padding bytes unsafe { slice::from_raw_parts(self.as_ptr().cast::>(), super::size_of::()) @@ -1115,6 +1121,35 @@ impl MaybeUninit { ) } } + + /// Converts `&T` to `&MaybeUninit`. + /// + /// The value stays initialized. This function changes only the type of the reference. + /// + /// There is no corresponding `from_mut` method, because it could allow writing uninitialized memory + /// into the original value. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_from_ref, maybe_uninit_as_bytes)] + /// use std::mem::MaybeUninit; + /// + /// let val = 0x12345678_u32; + /// let uninit = MaybeUninit::from_ref(&val); + /// let bytes = uninit.as_bytes(); + /// + /// // All bytes of a u32 are initialized, so assume_init is sound here: + /// let byte_val = unsafe { bytes[0].assume_init() }; + /// assert_eq!(byte_val, val.to_ne_bytes()[0]); + /// ``` + #[unstable(feature = "maybe_uninit_from_ref", issue = "165213")] + #[inline] + #[must_use] + pub const fn from_ref(r: &T) -> &MaybeUninit { + // SAFETY: `MaybeUninit` is repr(transparent) and every initialized T is a valid MaybeUninit + unsafe { &*ptr::from_ref(r).cast() } + } } impl [MaybeUninit] { @@ -1478,6 +1513,9 @@ impl [MaybeUninit] { /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still /// contain padding bytes which are left uninitialized. /// + /// This method requires `T: Freeze`. It's not available for types with interior mutability, + /// such as `Cell`. + /// /// # Examples /// /// ``` @@ -1492,7 +1530,10 @@ impl [MaybeUninit] { /// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]); /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] - pub const fn as_bytes(&self) -> &[MaybeUninit] { + pub const fn as_bytes(&self) -> &[MaybeUninit] + where + T: Freeze, + { // SAFETY: MaybeUninit is always valid, even for padding bytes unsafe { slice::from_raw_parts(self.as_ptr().cast::>(), super::size_of_val(self)) From d779c9be212f2c4e8b314470b5d8ad01def7626c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 21 Oct 2026 17:17:54 -0500 Subject: [PATCH 25/29] core: Rename `abort_immediate` to `crash` --- library/core/src/intrinsics/mod.rs | 10 +++--- library/core/src/process.rs | 32 +++++++++---------- .../core/src/slice/sort/stable/quicksort.rs | 2 +- library/std/src/process.rs | 2 +- tests/run-make/abort-behavior/main.rs | 4 +-- tests/run-make/abort-behavior/rmake.rs | 10 +++--- tests/ui/consts/const-eval/const_panic.rs | 2 +- tests/ui/consts/const-eval/const_panic.stderr | 6 ++-- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 64cf978a4b0e4..89ac4c0c956e6 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -618,10 +618,10 @@ pub fn rustc_peek(_: T) -> T; /// Ungracefully aborts the execution of the process. /// -/// This is the intrinsic for directly implementing [`core::process::abort_immediate`] which, on -/// most platforms, will invoke an invalid instruction. On Unix, the process will probably -/// terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or `SIGBUS`. The -/// precise behavior is not guaranteed and not stable. +/// This is the intrinsic for directly implementing [`core::process::crash`] which, on most +/// platforms, will invoke an invalid instruction. On Unix, the process will probably terminate with +/// a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or `SIGBUS`. The precise behavior is not +/// guaranteed and not stable. /// /// [`std::process::abort`](../../std/process/fn.abort.html) is to be preferred if possible, /// as its behavior is more user-friendly and more stable. @@ -629,7 +629,7 @@ pub fn rustc_peek(_: T) -> T; /// Note that, unlike most intrinsics, this is safe to call; it does not require an `unsafe` block. /// Therefore, implementations must not require the user to uphold any safety invariants. /// -/// The stabilized version of this intrinsic is [`core::process::abort_immediate`]. +/// The stabilized version of this intrinsic is [`core::process::crash`]. #[rustc_nounwind] #[rustc_intrinsic] pub const fn abort_immediate() -> !; diff --git a/library/core/src/process.rs b/library/core/src/process.rs index 12b2fdb46085d..2f116992e6d91 100644 --- a/library/core/src/process.rs +++ b/library/core/src/process.rs @@ -1,7 +1,7 @@ //! A module for working with processes. //! -//! Most process-related functionality requires std, but [`abort_immediate`] -//! is available on all targets. +//! Most process-related functionality requires std, but [`crash`] is available +//! on all targets. /// Terminates the process in a violent fashion. /// @@ -11,18 +11,18 @@ /// will be run, Rust IO buffers (eg, from `BufWriter`) will not be flushed, /// and C stdio buffers will not be flushed. /// -/// Unlike [`abort`](../../std/process/fn.abort.html), `abort_immediate` does -/// not attempt to match C `abort()` or otherwise perform a "clean" abort. -/// Instead, it emits code that will crash the process with as little overhead -/// as possible, such as a "halt and catch fire" style instruction. You should -/// generally prefer using `abort` instead except where the absolute minimum -/// overhead is required. +/// Unlike [`abort`](../../std/process/fn.abort.html), `crash` does not attempt +/// to match C `abort()` or otherwise perform a "clean" abort. Instead, it emits +/// code that will crash the process with as little overhead as possible, such +/// as a "halt and catch fire" style instruction. You should generally prefer +/// using `abort` instead except where the absolute minimum overhead is +/// required. /// /// # Platform-specific behavior /// -/// `abort_immediate` lowers to a trap instruction on *most* architectures; on -/// some architectures it simply lowers to call the unmangled `abort` function. -/// The exact behavior is architecture- and system-dependent. +/// `crash` lowers to a trap instruction on *most* architectures; on some +/// architectures it simply lowers to call the unmangled `abort` function. The +/// exact behavior is architecture- and system-dependent. /// /// On bare-metal (no OS) systems the trap instruction usually causes a /// *hardware* exception to be raised in a *synchronous* fashion; hardware @@ -45,14 +45,14 @@ /// fn main() { /// println!("aborting"); /// -/// process::abort_immediate(); +/// process::crash(); /// /// // execution never gets here /// } /// ``` /// -/// The `abort_immediate` function terminates the process, so the destructor -/// will not get run on the example below: +/// The `crash` function terminates the process, so the destructor will not get +/// run on the example below: /// /// ```no_run /// #![feature(abort_immediate)] @@ -69,7 +69,7 @@ /// /// fn main() { /// let _x = HasDrop; -/// process::abort_immediate(); +/// process::crash(); /// // the destructor implemented for HasDrop will never get run /// } /// ``` @@ -80,7 +80,7 @@ #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[doc(alias = "halt")] #[doc(alias = "trap")] -pub const fn abort_immediate() -> ! { +pub const fn crash() -> ! { crate::intrinsics::abort_immediate() } diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 1696a5e3c0277..e127978f01c9a 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -96,7 +96,7 @@ fn stable_partition bool>( let len = v.len(); if intrinsics::unlikely(scratch.len() < len || pivot_pos >= len) { - core::intrinsics::abort_immediate() + intrinsics::abort_immediate() } let v_base = v.as_ptr(); diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 7afda60d019ec..fdb21410c7623 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2641,7 +2641,7 @@ pub fn abort() -> ! { #[doc(inline)] #[unstable(feature = "abort_immediate", issue = "154601")] -pub use core::process::abort_immediate; +pub use core::process::crash; #[doc(inline)] #[unstable(feature = "breakpoint", issue = "133724")] pub use core::process::resumable_breakpoint; diff --git a/tests/run-make/abort-behavior/main.rs b/tests/run-make/abort-behavior/main.rs index db7401fafbf8a..01074417fe72f 100644 --- a/tests/run-make/abort-behavior/main.rs +++ b/tests/run-make/abort-behavior/main.rs @@ -4,7 +4,7 @@ fn main() { let arg = std::env::args().skip(1).next().expect("no argument passed"); match arg.as_str() { "abort" => std::process::abort(), - "abort_immediate" => std::process::abort_immediate(), - _ => panic!("unrecognized command {}", arg), + "crash" => std::process::crash(), + _ => panic!("unrecognized command {arg}"), } } diff --git a/tests/run-make/abort-behavior/rmake.rs b/tests/run-make/abort-behavior/rmake.rs index 2d644777fdd45..7cef4f347dad4 100644 --- a/tests/run-make/abort-behavior/rmake.rs +++ b/tests/run-make/abort-behavior/rmake.rs @@ -7,21 +7,21 @@ use run_make_support::{bin_name, run_fail_with_args, rustc}; #[derive(Debug)] enum Variant { Abort, - AbortImmediate, + Crash, } fn main() { rustc().input("main.rs").run(); check_one(Variant::Abort); - check_one(Variant::AbortImmediate); + check_one(Variant::Crash); } fn check_one(variant: Variant) { println!("checking variant {variant:?}"); let arg = match variant { Variant::Abort => "abort", - Variant::AbortImmediate => "abort_immediate", + Variant::Crash => "crash", }; let bin = &bin_name("main"); let out = run_fail_with_args(bin, &[arg]); @@ -40,7 +40,7 @@ fn check_one(variant: Variant) { let sig = status.signal().expect("no signal recorded"); match variant { Variant::Abort => assert_eq!(sig, libc::SIGABRT), - Variant::AbortImmediate => assert_matches!(sig, libc::SIGILL | libc::SIGTRAP), + Variant::Crash => assert_matches!(sig, libc::SIGILL | libc::SIGTRAP), }; } windows => { @@ -52,7 +52,7 @@ fn check_one(variant: Variant) { let code = status.code().unwrap(); let expected = match variant { Variant::Abort => STATUS_STACK_BUFFER_OVERRUN.0, - Variant::AbortImmediate => STATUS_ILLEGAL_INSTRUCTION.0, + Variant::Crash => STATUS_ILLEGAL_INSTRUCTION.0, }; assert_eq!(code, expected); } diff --git a/tests/ui/consts/const-eval/const_panic.rs b/tests/ui/consts/const-eval/const_panic.rs index e4fd30d2e1678..a3f299decd0ba 100644 --- a/tests/ui/consts/const-eval/const_panic.rs +++ b/tests/ui/consts/const-eval/const_panic.rs @@ -41,5 +41,5 @@ const W_CORE: () = core::panic!(MSG); const W2_CORE: () = core::panic!("{}", MSG); //~^ ERROR evaluation panicked -const ABORT: () = core::process::abort_immediate(); +const ABORT: () = core::process::crash(); //~^ ERROR the program aborted execution diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr index c91151b137fbe..16facaa2d4962 100644 --- a/tests/ui/consts/const-eval/const_panic.stderr +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -73,10 +73,10 @@ LL | const W2_CORE: () = core::panic!("{}", MSG); error[E0080]: the program aborted execution --> $DIR/const_panic.rs:44:19 | -LL | const ABORT: () = core::process::abort_immediate(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ABORT` failed inside this call +LL | const ABORT: () = core::process::crash(); + | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ABORT` failed inside this call | -note: inside `std::process::abort_immediate` +note: inside `crash` --> $SRC_DIR/core/src/process.rs:LL:COL error: aborting due to 13 previous errors From f8613c8529696f63ee9cc2acc0fd8c7069932304 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Sat, 31 Oct 2026 14:37:42 +0800 Subject: [PATCH 26/29] Add `feature(stdarch_loongarch)` for bootstrap --- compiler/rustc_span/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 03dc07870345a..44fbbbaccd66f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,6 +17,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(all(bootstrap, target_arch = "loongarch64"), feature(stdarch_loongarch))] #![feature(core_io_borrowed_buf)] #![feature(decl_macro)] #![feature(diagnostic_on_unknown)] From b33e5d4592c0722a4dd4ddf9c744ef6a0e4188ba Mon Sep 17 00:00:00 2001 From: Walnut Date: Sat, 31 Oct 2026 04:27:38 -0500 Subject: [PATCH 27/29] Fix error output for invalid `SBValue` children --- src/etc/debugger_tester/lldb/from_lldb.py | 31 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/etc/debugger_tester/lldb/from_lldb.py b/src/etc/debugger_tester/lldb/from_lldb.py index 1fcf78b7930cd..77530bb30b26e 100644 --- a/src/etc/debugger_tester/lldb/from_lldb.py +++ b/src/etc/debugger_tester/lldb/from_lldb.py @@ -15,6 +15,8 @@ import lldb import lldb_lookup +from debugger_tester.common import print_error + from ..common import ( BLESS, TARGET, @@ -266,9 +268,18 @@ def child_from_lldb(child: lldb.SBValue) -> Child: else: value = None - children = [ - child_from_lldb(child.GetChildAtIndex(i)) for i in range(child.GetNumChildren()) - ] + children = [] + + for i in range(child.GetNumChildren()): + inner_child = child.GetChildAtIndex(i) + if inner_child.IsValid(): + children.append(child_from_lldb(inner_child)) + else: + print_error( + child.get_expr_path(), + f"GetChildAtIndex({i}) returned an invalid SBValue", + ) + children.append(Child("", "", None, None)) if is_arraylike(children): children = make_arraylike(children) @@ -327,9 +338,17 @@ def variable_from_lldb(var: lldb.SBValue) -> Variable: else: pretty_print = None - children = [ - child_from_lldb(var.GetChildAtIndex(i)) for i in range(var.GetNumChildren()) - ] + children = [] + + for i in range(var.GetNumChildren()): + child = var.GetChildAtIndex(i) + if child.IsValid(): + children.append(child_from_lldb(child)) + else: + print_error( + var.GetName(), f"GetChildAtIndex({i}) returned an invalid SBValue" + ) + children.append(Child("", "", None, None)) if is_arraylike(children): children = make_arraylike(children) From 57bb231158cadc1339613521dcaac2c0ced819d3 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 31 Oct 2026 14:25:17 +0100 Subject: [PATCH 28/29] use `[expr; N]` literals for long arrays of the same element --- compiler/rustc_codegen_llvm/src/type_of.rs | 43 ++++------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 0624d8db460c0..3c87b556ec433 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -33,42 +33,13 @@ fn uncached_llvm_type<'a, 'tcx>( let vector_type = cx.type_scalable_vector(element, count.as_u64()); return match number_of_vectors.0 { 1 => vector_type, - 2 => cx.type_struct(&[vector_type, vector_type], false), - 3 => cx.type_struct(&[vector_type, vector_type, vector_type], false), - 4 => cx.type_struct(&[vector_type, vector_type, vector_type, vector_type], false), - 5 => cx.type_struct( - &[vector_type, vector_type, vector_type, vector_type, vector_type], - false, - ), - 6 => cx.type_struct( - &[vector_type, vector_type, vector_type, vector_type, vector_type, vector_type], - false, - ), - 7 => cx.type_struct( - &[ - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - ], - false, - ), - 8 => cx.type_struct( - &[ - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - vector_type, - ], - false, - ), + 2 => cx.type_struct(&[vector_type; 2], false), + 3 => cx.type_struct(&[vector_type; 3], false), + 4 => cx.type_struct(&[vector_type; 4], false), + 5 => cx.type_struct(&[vector_type; 5], false), + 6 => cx.type_struct(&[vector_type; 6], false), + 7 => cx.type_struct(&[vector_type; 7], false), + 8 => cx.type_struct(&[vector_type; 8], false), _ => bug!("`#[rustc_scalable_vector]` tuple struct with too many fields"), }; } From 3e28b256b5d135f7f88df192b57bc9def95485dd Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 31 Oct 2026 14:32:39 +0100 Subject: [PATCH 29/29] remove the `packed` argument from `type_struct` and just have a separate `type_packed_struct` helper for the one case where we don't pass `false` to that function. --- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_codegen_llvm/src/asm.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 6 ++-- .../src/builder/autodiff.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +-- compiler/rustc_codegen_llvm/src/type_.rs | 15 ++++----- compiler/rustc_codegen_llvm/src/type_of.rs | 31 +++++++++---------- 7 files changed, 30 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index e50fc4bea82fd..49bcd7aad6895 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -217,7 +217,7 @@ impl LlvmType for CastTarget { let prefix_args = self.prefix.iter().map(|reg| reg.llvm_type(cx)); let rest_args = (0..rest_count).map(|_| rest_ll_unit); let args: Vec<_> = prefix_args.chain(rest_args).collect(); - cx.type_struct(&args, false) + cx.type_struct(&args) } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 21888720524a5..8083bb239e2d6 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -335,7 +335,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let output_type = match &output_types[..] { [] => self.type_void(), [ty] => ty, - tys => self.type_struct(tys, false), + tys => self.type_struct(tys), }; let dialect = match asm_arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9e3492d0ca696..0dd05cc619b74 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1305,7 +1305,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) { - let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); + let ty = self.type_struct(&[self.type_ptr(), self.type_i32()]); let landing_pad = self.landing_pad(ty, pers_fn, 0); unsafe { llvm::LLVMSetCleanup(landing_pad, llvm::TRUE); @@ -1314,13 +1314,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn filter_landing_pad(&mut self, pers_fn: &'ll Value) { - let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); + let ty = self.type_struct(&[self.type_ptr(), self.type_i32()]); let landing_pad = self.landing_pad(ty, pers_fn, 1); self.add_clause(landing_pad, self.const_array(self.type_ptr(), &[])); } fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) { - let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); + let ty = self.type_struct(&[self.type_ptr(), self.type_i32()]); let mut exn = self.const_poison(ty); exn = self.insert_value(exn, exn0, 0); exn = self.insert_value(exn, exn1, 1); diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index b7f1521c7fe3e..2b7be60277aa4 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -369,7 +369,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( let call = bx.call(enzyme_ty, None, None, ad_fn, ReturnSlot::Direct, &args, None, None); let fn_ret_ty = bx.cx.val_ty(call); - if fn_ret_ty == bx.cx.type_void() || fn_ret_ty == bx.cx.type_struct(&[], false) { + if fn_ret_ty == bx.cx.type_void() || fn_ret_ty == bx.cx.type_struct(&[]) { // If we return void or an empty struct, then our caller (due to how we generated it) // does not expect a return value. As such, we have no pointer (or place) into which // we could store our value, and would store into an undef, which would cause UB. diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2b529aa2c5360..b3735d7fba0f8 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -398,7 +398,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // FIXME: could be `trunc nuw`, even for signed. let high = self.trunc(high, narrow_llty); - let pair_llty = self.type_struct(&[narrow_llty, narrow_llty], false); + let pair_llty = self.type_struct(&[narrow_llty, narrow_llty]); let pair = self.const_poison(pair_llty); let pair = self.insert_value(pair, low, 0); let pair = self.insert_value(pair, high, 1); @@ -1669,7 +1669,7 @@ fn codegen_gnu_try<'ll, 'tcx>( // the landing pad clauses the exception's type had been matched to. // rust_try ignores the selector. bx.switch_to_block(catch); - let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false); + let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()]); let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1); let tydesc = bx.const_null(bx.type_ptr()); bx.add_clause(vals, tydesc); diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 0244706033641..0a0c82650984f 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -168,14 +168,15 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { unsafe { llvm::LLVMInt1TypeInContext(self.llcx()) } } - pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { + pub(crate) fn type_struct(&self, els: &[&'ll Type]) -> &'ll Type { unsafe { - llvm::LLVMStructTypeInContext( - self.llcx(), - els.as_ptr(), - els.len() as c_uint, - packed.to_llvm_bool(), - ) + llvm::LLVMStructTypeInContext(self.llcx(), els.as_ptr(), els.len() as c_uint, FALSE) + } + } + + pub(crate) fn type_packed_struct(&self, els: &[&'ll Type]) -> &'ll Type { + unsafe { + llvm::LLVMStructTypeInContext(self.llcx(), els.as_ptr(), els.len() as c_uint, TRUE) } } diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 3c87b556ec433..79eeae4c977a2 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -33,13 +33,13 @@ fn uncached_llvm_type<'a, 'tcx>( let vector_type = cx.type_scalable_vector(element, count.as_u64()); return match number_of_vectors.0 { 1 => vector_type, - 2 => cx.type_struct(&[vector_type; 2], false), - 3 => cx.type_struct(&[vector_type; 3], false), - 4 => cx.type_struct(&[vector_type; 4], false), - 5 => cx.type_struct(&[vector_type; 5], false), - 6 => cx.type_struct(&[vector_type; 6], false), - 7 => cx.type_struct(&[vector_type; 7], false), - 8 => cx.type_struct(&[vector_type; 8], false), + 2 => cx.type_struct(&[vector_type; 2]), + 3 => cx.type_struct(&[vector_type; 3]), + 4 => cx.type_struct(&[vector_type; 4]), + 5 => cx.type_struct(&[vector_type; 5]), + 6 => cx.type_struct(&[vector_type; 6]), + 7 => cx.type_struct(&[vector_type; 7]), + 8 => cx.type_struct(&[vector_type; 8]), _ => bug!("`#[rustc_scalable_vector]` tuple struct with too many fields"), }; } @@ -75,11 +75,11 @@ fn uncached_llvm_type<'a, 'tcx>( match layout.fields { FieldsShape::Primitive | FieldsShape::Union(_) => { let fill = cx.type_padding_filler(layout.size, layout.align.abi); - let packed = false; match name { - None => cx.type_struct(&[fill], packed), + None => cx.type_struct(&[fill]), Some(ref name) => { let llty = cx.type_named_struct(name); + let packed = false; cx.set_struct_body(llty, &[fill], packed); llty } @@ -89,7 +89,7 @@ fn uncached_llvm_type<'a, 'tcx>( FieldsShape::Arbitrary { .. } => match name { None => { let (llfields, packed) = struct_llfields(cx, layout); - cx.type_struct(&llfields, packed) + if packed { cx.type_packed_struct(&llfields) } else { cx.type_struct(&llfields) } } Some(ref name) => { let llty = cx.type_named_struct(name); @@ -265,13 +265,10 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair { .. } => { // An immediate pair always contains just the two elements, without any padding // filler, as it should never be stored to memory. - return cx.type_struct( - &[ - self.scalar_pair_element_llvm_type(cx, 0, true), - self.scalar_pair_element_llvm_type(cx, 1, true), - ], - false, - ); + return cx.type_struct(&[ + self.scalar_pair_element_llvm_type(cx, 0, true), + self.scalar_pair_element_llvm_type(cx, 1, true), + ]); } _ => {} };