Skip to content

Stabilize const_float_classify #130157

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 2 commits into from
Oct 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
@@ -1739,7 +1739,7 @@ pub(crate) enum InvalidNanComparisons {
#[diag(lint_invalid_nan_comparisons_eq_ne)]
EqNe {
#[subdiagnostic]
suggestion: Option<InvalidNanComparisonsSuggestion>,
suggestion: InvalidNanComparisonsSuggestion,
},
#[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)]
LtLeGtGe,
22 changes: 9 additions & 13 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
@@ -605,36 +605,32 @@ fn lint_nan<'tcx>(
}

fn eq_ne(
cx: &LateContext<'_>,
e: &hir::Expr<'_>,
l: &hir::Expr<'_>,
r: &hir::Expr<'_>,
f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion,
) -> InvalidNanComparisons {
// FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const.
let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| {
if let Some(l_span) = l.span.find_ancestor_inside(e.span)
&& let Some(r_span) = r.span.find_ancestor_inside(e.span)
{
f(l_span, r_span)
} else {
InvalidNanComparisonsSuggestion::Spanless
}
});
let suggestion = if let Some(l_span) = l.span.find_ancestor_inside(e.span)
&& let Some(r_span) = r.span.find_ancestor_inside(e.span)
{
f(l_span, r_span)
} else {
InvalidNanComparisonsSuggestion::Spanless
};

InvalidNanComparisons::EqNe { suggestion }
}

let lint = match binop.node {
hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => {
eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
nan_plus_binop: l_span.until(r_span),
float: r_span.shrink_to_hi(),
neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()),
})
}
hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => {
eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful {
nan_plus_binop: l_span.shrink_to_hi().to(r_span),
float: l_span.shrink_to_hi(),
neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()),
1 change: 0 additions & 1 deletion library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -121,7 +121,6 @@
#![feature(const_cell_into_inner)]
#![feature(const_eval_select)]
#![feature(const_exact_div)]
#![feature(const_float_classify)]
#![feature(const_fmt_arguments_new)]
#![feature(const_hash)]
#![feature(const_heap)]
12 changes: 6 additions & 6 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
@@ -288,7 +288,7 @@ impl f128 {
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub(crate) const fn abs_private(self) -> f128 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe {
@@ -319,7 +319,7 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_infinite(self) -> bool {
(self == f128::INFINITY) | (self == f128::NEG_INFINITY)
}
@@ -346,7 +346,7 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
// the comparison is not true, exactly as desired.
@@ -380,7 +380,7 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
}
@@ -412,7 +412,7 @@ impl f128 {
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
}
@@ -437,7 +437,7 @@ impl f128 {
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn classify(self) -> FpCategory {
// Other float types suffer from various platform bugs that violate the usual IEEE semantics
// and also make bitwise classification not always work reliably. However, `f128` cannot fit
12 changes: 6 additions & 6 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
@@ -282,7 +282,7 @@ impl f16 {
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub(crate) const fn abs_private(self) -> f16 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
@@ -310,7 +310,7 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_infinite(self) -> bool {
(self == f16::INFINITY) | (self == f16::NEG_INFINITY)
}
@@ -336,7 +336,7 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
// the comparison is not true, exactly as desired.
@@ -368,7 +368,7 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
}
@@ -398,7 +398,7 @@ impl f16 {
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
}
@@ -422,7 +422,7 @@ impl f16 {
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn classify(self) -> FpCategory {
// A previous implementation for f32/f64 tried to only use bitmask-based checks,
// using `to_bits` to transmute the float to its bit repr and match on that.
17 changes: 8 additions & 9 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
@@ -516,7 +516,7 @@ impl f32 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
pub const fn is_nan(self) -> bool {
@@ -527,7 +527,6 @@ impl f32 {
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f32 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self) & !Self::SIGN_MASK) }
@@ -550,7 +549,7 @@ impl f32 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_infinite(self) -> bool {
// Getting clever with transmutation can result in incorrect answers on some FPUs
@@ -575,7 +574,7 @@ impl f32 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
@@ -603,7 +602,7 @@ impl f32 {
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
#[must_use]
#[stable(feature = "is_subnormal", since = "1.53.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
@@ -630,7 +629,7 @@ impl f32 {
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
@@ -650,7 +649,7 @@ impl f32 {
/// assert_eq!(inf.classify(), FpCategory::Infinite);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
pub const fn classify(self) -> FpCategory {
// A previous implementation tried to only use bitmask-based checks,
// using f32::to_bits to transmute the float to its bit repr and match on that.
@@ -710,7 +709,7 @@ impl f32 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_sign_positive(self) -> bool {
!self.is_sign_negative()
@@ -735,7 +734,7 @@ impl f32 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
17 changes: 8 additions & 9 deletions library/core/src/num/f64.rs
Original file line number Diff line number Diff line change
@@ -515,7 +515,7 @@ impl f64 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
pub const fn is_nan(self) -> bool {
@@ -526,7 +526,6 @@ impl f64 {
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f64 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self) & !Self::SIGN_MASK) }
@@ -549,7 +548,7 @@ impl f64 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_infinite(self) -> bool {
// Getting clever with transmutation can result in incorrect answers on some FPUs
@@ -574,7 +573,7 @@ impl f64 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
@@ -602,7 +601,7 @@ impl f64 {
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
#[must_use]
#[stable(feature = "is_subnormal", since = "1.53.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
@@ -629,7 +628,7 @@ impl f64 {
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
@@ -649,7 +648,7 @@ impl f64 {
/// assert_eq!(inf.classify(), FpCategory::Infinite);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
pub const fn classify(self) -> FpCategory {
// A previous implementation tried to only use bitmask-based checks,
// using f64::to_bits to transmute the float to its bit repr and match on that.
@@ -705,7 +704,7 @@ impl f64 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_sign_positive(self) -> bool {
!self.is_sign_negative()
@@ -739,7 +738,7 @@ impl f64 {
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[rustc_const_stable(feature = "const_float_classify", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn is_sign_negative(self) -> bool {
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
1 change: 0 additions & 1 deletion tests/ui/float/classify-runtime-const.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@

#![feature(f16_const)]
#![feature(f128_const)]
#![feature(const_float_classify)]

use std::hint::black_box;
use std::num::FpCategory::*;
1 change: 0 additions & 1 deletion tests/ui/float/conv-bits-runtime-const.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@

// This tests the float classification functions, for regular runtime code and for const evaluation.

#![feature(const_float_classify)]
#![feature(f16)]
#![feature(f128)]
#![feature(f16_const)]
5 changes: 5 additions & 0 deletions tests/ui/lint/invalid-nan-comparison.stderr
Original file line number Diff line number Diff line change
@@ -5,6 +5,11 @@ LL | const TEST: bool = 5f32 == f32::NAN;
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(invalid_nan_comparisons)]` on by default
help: use `f32::is_nan()` or `f64::is_nan()` instead
|
LL - const TEST: bool = 5f32 == f32::NAN;
LL + const TEST: bool = 5f32.is_nan();
|

warning: incorrect NaN comparison, NaN cannot be directly compared to itself
--> $DIR/invalid-nan-comparison.rs:14:5
Loading