From acd02b866bf58c99d56f45a4d7887f861b746f44 Mon Sep 17 00:00:00 2001 From: Autumn Dickinson Date: Wed, 9 Sep 2026 13:38:54 -0700 Subject: [PATCH 01/14] document that `!` does bitwise and logical negation --- library/core/src/ops/bit.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index 7c008531c1f5a..5b80b4edc20de 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -1,4 +1,5 @@ -/// The unary logical negation operator `!`. +/// The unary negation operator `!`. It performs either logical or bitwise negation, +/// depending on the type. /// /// # Examples /// @@ -37,15 +38,23 @@ pub const trait Not { #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// Performs the unary `!` operation. + /// Performs the unary `!` operation using logical or bitwise negation. /// /// # Examples /// /// ``` + /// // Logical negation changes between true and false: /// assert_eq!(!true, false); /// assert_eq!(!false, true); + /// + /// // Bitwise negation changes between 0 and 1 in the binary + /// // representation of integers: /// assert_eq!(!1u8, 254); /// assert_eq!(!0u8, 255); + /// + /// // The same examples, represented in binary: + /// assert_eq!(!0b0000_0001u8, 0b1111_1110); + /// assert_eq!(!0b0000_0000u8, 0b1111_1111); /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] From 6fc1dc1bbfd90a36ba80662c73378054a632a59c Mon Sep 17 00:00:00 2001 From: Yu Date: Tue, 13 Oct 2026 21:03:02 +0800 Subject: [PATCH 02/14] lint: suggest fXX::is_nan for unsuffixed NaN comparisons --- compiler/rustc_lint/src/diagnostics.rs | 16 ++ compiler/rustc_lint/src/types.rs | 163 ++++++++++++++---- .../invalid-nan-comparison-suggestion.fixed | 42 +++++ .../lint/invalid-nan-comparison-suggestion.rs | 42 +++++ .../invalid-nan-comparison-suggestion.stderr | 114 +++++++++++- 5 files changed, 336 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index 601f1213650e1..cdb962a12d111 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -2334,6 +2334,22 @@ pub(crate) enum InvalidNanComparisonsSuggestion { #[suggestion_part(code = "")] nan_plus_binop: Span, }, + #[multipart_suggestion( + "use `f32::is_nan()` or `f64::is_nan()` instead", + style = "verbose", + applicability = "machine-applicable" + )] + Ufcs { + prefix: String, + #[suggestion_part(code = "{prefix}")] + prefix_span: Span, + #[suggestion_part(code = ")")] + close_span: Span, + #[suggestion_part(code = "")] + remove_nan: Span, + #[suggestion_part(code = "")] + remove_borrow: Option, + }, #[help("use `f32::is_nan()` or `f64::is_nan()` instead")] Spanless, } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9897e9cbb4f07..7549014dab97a 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -229,58 +229,145 @@ fn lint_nan<'tcx>( l: &'tcx hir::Expr<'tcx>, r: &'tcx hir::Expr<'tcx>, ) { - fn is_nan(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + fn nan_ty(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { let expr = expr.peel_blocks().peel_borrows(); - match expr.kind { - ExprKind::Path(qpath) => { - let Some(def_id) = cx.typeck_results().qpath_res(&qpath, expr.hir_id).opt_def_id() - else { - return false; - }; + let ExprKind::Path(qpath) = expr.kind else { return None }; + let def_id = cx.typeck_results().qpath_res(&qpath, expr.hir_id).opt_def_id()?; + if !matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::f16_nan | sym::f32_nan | sym::f64_nan | sym::f128_nan) + ) { + return None; + } + match cx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() { + ty::Float(fty) => Some(*fty), + _ => None, + } + } - matches!( - cx.tcx.get_diagnostic_name(def_id), - Some(sym::f16_nan | sym::f32_nan | sym::f64_nan | sym::f128_nan) - ) - } - _ => false, + fn is_primitive_float(mut ty: &hir::Ty<'_>) -> bool { + while let hir::TyKind::Ref(_, inner, _) = ty.kind { + ty = inner; } + matches!( + ty.kind, + hir::TyKind::Path(hir::QPath::Resolved(_, path)) + if matches!(path.res, hir::def::Res::PrimTy(hir::PrimTy::Float(_))) + ) } - fn eq_ne( - e: &hir::Expr<'_>, - l: &hir::Expr<'_>, - r: &hir::Expr<'_>, - f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion, - ) -> InvalidNanComparisons { - 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) + // `true` when `expr.is_nan()` still type-checks after this comparison is removed. + // `let [mut] b = &3.3; b != &f64::NAN` is `&f64` only because of that comparison, so + // `b.is_nan()` leaves `{float}` and does not compile. `let b: f64 = 3.3` does. + fn can_suggest_is_nan_method<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) -> bool { + let mut cursor = expr.peel_blocks().peel_borrows(); + while let ExprKind::Path(qpath) = &cursor.kind + && let hir::def::Res::Local(hir_id) = cx.qpath_res(qpath, cursor.hir_id) + && let hir::Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id) + { + if local.ty.is_some_and(is_primitive_float) { + return true; + } + if let hir::PatKind::Binding(..) = local.pat.kind + && let Some(init) = local.init + { + cursor = init.peel_blocks().peel_borrows(); + } else { + break; + } + } + if let ExprKind::Lit(lit) = cursor.kind + && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node { - f(l_span, r_span) + return false; + } + cx.typeck_results().expr_ty_opt(cursor).is_some_and(|ty| ty.peel_refs().is_floating_point()) + } + + fn eq_ne_suggestion<'a>( + cx: &LateContext<'a>, + cmp: &'a hir::Expr<'a>, + value: &'a hir::Expr<'a>, + nan: &'a hir::Expr<'a>, + float_ty: ty::FloatTy, + is_ne: bool, + ) -> InvalidNanComparisonsSuggestion { + let (Some(value_span), Some(nan_span)) = + (value.span.find_ancestor_inside(cmp.span), nan.span.find_ancestor_inside(cmp.span)) + else { + return InvalidNanComparisonsSuggestion::Spanless; + }; + let remove_nan = if nan_span.lo() < value_span.lo() { + nan_span.until(value_span) } else { - InvalidNanComparisonsSuggestion::Spanless + value_span.shrink_to_hi().to(nan_span) }; - InvalidNanComparisons::EqNe { suggestion } + if can_suggest_is_nan_method(cx, value) { + return InvalidNanComparisonsSuggestion::Spanful { + neg: is_ne.then(|| value_span.shrink_to_lo()), + float: value_span.shrink_to_hi(), + nan_plus_binop: remove_nan, + }; + } + + let Some(mut ty) = cx.typeck_results().expr_ty_opt(value) else { + return InvalidNanComparisonsSuggestion::Spanless; + }; + let mut operand = value.peel_blocks(); + let Some(mut operand_span) = operand.span.find_ancestor_inside(value_span) else { + return InvalidNanComparisonsSuggestion::Spanless; + }; + let outer_span = operand_span; + let mut deref_count = 0; + while let ty::Ref(_, inner, _) = *ty.kind() { + if let ExprKind::AddrOf(_, _, inner_expr) = operand.kind + && let peeled = inner_expr.peel_blocks() + && let Some(peeled_span) = peeled.span.find_ancestor_inside(operand_span) + { + operand = peeled; + operand_span = peeled_span; + } else { + deref_count += 1; + } + ty = inner; + } + let matches_float = match *ty.kind() { + ty::Float(fty) => fty == float_ty, + ty::Infer(ty::FloatVar(_)) => true, + _ => false, + }; + if !matches_float { + return InvalidNanComparisonsSuggestion::Spanless; + } + let written_borrow = outer_span.until(operand_span); + let neg = if is_ne { "!" } else { "" }; + InvalidNanComparisonsSuggestion::Ufcs { + prefix: format!("{neg}{}::is_nan({}", float_ty.name_str(), "*".repeat(deref_count)), + prefix_span: operand_span.shrink_to_lo(), + close_span: operand_span.shrink_to_hi(), + remove_nan, + remove_borrow: (!written_borrow.is_empty()).then_some(written_borrow), + } } + let l_nan = nan_ty(cx, l); + let r_nan = nan_ty(cx, r); + let is_ne = binop == hir::BinOpKind::Ne; let lint = match binop { - hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => { - 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 == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()), - }) - } - hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => { - 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 == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()), - }) + hir::BinOpKind::Eq | hir::BinOpKind::Ne => { + let Some((value, nan, float_ty)) = l_nan + .map(|float_ty| (r, l, float_ty)) + .or_else(|| r_nan.map(|float_ty| (l, r, float_ty))) + else { + return; + }; + InvalidNanComparisons::EqNe { + suggestion: eq_ne_suggestion(cx, e, value, nan, float_ty, is_ne), + } } hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge - if is_nan(cx, l) || is_nan(cx, r) => + if l_nan.is_some() || r_nan.is_some() => { InvalidNanComparisons::LtLeGtGe } diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed index 2d88c274080b6..39d2ba3e93788 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed @@ -39,6 +39,38 @@ fn main() { let _ = !b.is_nan(); + // Issue #164143: an unsuffixed float is constrained by the `NAN` operand. + // Suggesting `.is_nan()` drops that constraint and does not compile. + let b = &3.3; + if !f64::is_nan(*b) {} + //~^ WARN incorrect NaN comparison + + let mut m = &3.3; + if !f64::is_nan(*m) { + //~^ WARN incorrect NaN comparison + m = &1.0; + } + let _ = m; + + let _ = f64::is_nan(3.3); + //~^ WARN incorrect NaN comparison + + let _ = !f64::is_nan(3.3); + //~^ WARN incorrect NaN comparison + + let suffixed = 3.3f64; + let copied = suffixed; + let _ = !copied.is_nan(); + //~^ WARN incorrect NaN comparison + + let ascribed: f64 = 3.3; + let _ = !ascribed.is_nan(); + //~^ WARN incorrect NaN comparison + + parameter(1.0); + parameter_ref(&1.0); + let _ = |x: f64| !x.is_nan(); //~ WARN incorrect NaN comparison + #[allow(unused_macros)] macro_rules! nan { () => { f32::NAN }; } macro_rules! number { () => { 5f32 }; } @@ -48,3 +80,13 @@ fn main() { let _ = !number!().is_nan(); //~^ WARN incorrect NaN comparison } + +fn parameter(x: f64) { + let _ = x.is_nan(); + //~^ WARN incorrect NaN comparison +} + +fn parameter_ref(x: &f32) { + if !x.is_nan() {} + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.rs b/tests/ui/lint/invalid-nan-comparison-suggestion.rs index 9175344786948..18e4a4093d10f 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.rs +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.rs @@ -42,6 +42,38 @@ fn main() { &f32::NAN }; + // Issue #164143: an unsuffixed float is constrained by the `NAN` operand. + // Suggesting `.is_nan()` drops that constraint and does not compile. + let b = &3.3; + if b != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let mut m = &3.3; + if m != &f64::NAN { + //~^ WARN incorrect NaN comparison + m = &1.0; + } + let _ = m; + + let _ = 3.3 == f64::NAN; + //~^ WARN incorrect NaN comparison + + let _ = &3.3 != &f64::NAN; + //~^ WARN incorrect NaN comparison + + let suffixed = 3.3f64; + let copied = suffixed; + let _ = copied != f64::NAN; + //~^ WARN incorrect NaN comparison + + let ascribed: f64 = 3.3; + let _ = ascribed != f64::NAN; + //~^ WARN incorrect NaN comparison + + parameter(1.0); + parameter_ref(&1.0); + let _ = |x: f64| x != f64::NAN; //~ WARN incorrect NaN comparison + #[allow(unused_macros)] macro_rules! nan { () => { f32::NAN }; } macro_rules! number { () => { 5f32 }; } @@ -51,3 +83,13 @@ fn main() { let _ = number!() != nan!(); //~^ WARN incorrect NaN comparison } + +fn parameter(x: f64) { + let _ = x == f64::NAN; + //~^ WARN incorrect NaN comparison +} + +fn parameter_ref(x: &f32) { + if x != &f32::NAN {} + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr index f9b1428de464c..5252977148e09 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr @@ -138,7 +138,91 @@ LL + !b.is_nan(); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:49:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:48:8 + | +LL | if b != &f64::NAN {} + | ^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if b != &f64::NAN {} +LL + if !f64::is_nan(*b) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:52:8 + | +LL | if m != &f64::NAN { + | ^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if m != &f64::NAN { +LL + if !f64::is_nan(*m) { + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:58:13 + | +LL | let _ = 3.3 == f64::NAN; + | ^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = 3.3 == f64::NAN; +LL + let _ = f64::is_nan(3.3); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:61:13 + | +LL | let _ = &3.3 != &f64::NAN; + | ^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = &3.3 != &f64::NAN; +LL + let _ = !f64::is_nan(3.3); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:66:13 + | +LL | let _ = copied != f64::NAN; + | ^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = copied != f64::NAN; +LL + let _ = !copied.is_nan(); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:70:13 + | +LL | let _ = ascribed != f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = ascribed != f64::NAN; +LL + let _ = !ascribed.is_nan(); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:75:22 + | +LL | let _ = |x: f64| x != f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = |x: f64| x != f64::NAN; +LL + let _ = |x: f64| !x.is_nan(); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:81:13 | LL | let _ = nan!() == number!(); | ^^^^^^^^^^^^^^^^^^^ @@ -150,7 +234,7 @@ LL + let _ = number!().is_nan(); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:51:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:83:13 | LL | let _ = number!() != nan!(); | ^^^^^^^^^^^^^^^^^^^ @@ -161,5 +245,29 @@ LL - let _ = number!() != nan!(); LL + let _ = !number!().is_nan(); | -warning: 13 warnings emitted +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:88:13 + | +LL | let _ = x == f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = x == f64::NAN; +LL + let _ = x.is_nan(); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:93:8 + | +LL | if x != &f32::NAN {} + | ^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if x != &f32::NAN {} +LL + if !x.is_nan() {} + | + +warning: 22 warnings emitted From 4f9916a7b7dba2794fa0825f778a6228586ba787 Mon Sep 17 00:00:00 2001 From: Yu Date: Tue, 13 Oct 2026 23:49:26 +0800 Subject: [PATCH 03/14] lint: use UFCS for NaN comparison suggestions --- compiler/rustc_lint/src/diagnostics.rs | 13 --- compiler/rustc_lint/src/types.rs | 47 -------- .../invalid-nan-comparison-suggestion.fixed | 52 ++++++--- .../lint/invalid-nan-comparison-suggestion.rs | 16 +++ .../invalid-nan-comparison-suggestion.stderr | 104 +++++++++++++----- tests/ui/lint/invalid-nan-comparison.stderr | 34 +++--- 6 files changed, 143 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index cdb962a12d111..ea36a485fc3ac 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -2321,19 +2321,6 @@ pub(crate) enum InvalidNanComparisons { #[derive(Subdiagnostic)] pub(crate) enum InvalidNanComparisonsSuggestion { - #[multipart_suggestion( - "use `f32::is_nan()` or `f64::is_nan()` instead", - style = "verbose", - applicability = "machine-applicable" - )] - Spanful { - #[suggestion_part(code = "!")] - neg: Option, - #[suggestion_part(code = ".is_nan()")] - float: Span, - #[suggestion_part(code = "")] - nan_plus_binop: Span, - }, #[multipart_suggestion( "use `f32::is_nan()` or `f64::is_nan()` instead", style = "verbose", diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 7549014dab97a..4769cb7bf485c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -245,45 +245,6 @@ fn lint_nan<'tcx>( } } - fn is_primitive_float(mut ty: &hir::Ty<'_>) -> bool { - while let hir::TyKind::Ref(_, inner, _) = ty.kind { - ty = inner; - } - matches!( - ty.kind, - hir::TyKind::Path(hir::QPath::Resolved(_, path)) - if matches!(path.res, hir::def::Res::PrimTy(hir::PrimTy::Float(_))) - ) - } - - // `true` when `expr.is_nan()` still type-checks after this comparison is removed. - // `let [mut] b = &3.3; b != &f64::NAN` is `&f64` only because of that comparison, so - // `b.is_nan()` leaves `{float}` and does not compile. `let b: f64 = 3.3` does. - fn can_suggest_is_nan_method<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) -> bool { - let mut cursor = expr.peel_blocks().peel_borrows(); - while let ExprKind::Path(qpath) = &cursor.kind - && let hir::def::Res::Local(hir_id) = cx.qpath_res(qpath, cursor.hir_id) - && let hir::Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id) - { - if local.ty.is_some_and(is_primitive_float) { - return true; - } - if let hir::PatKind::Binding(..) = local.pat.kind - && let Some(init) = local.init - { - cursor = init.peel_blocks().peel_borrows(); - } else { - break; - } - } - if let ExprKind::Lit(lit) = cursor.kind - && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node - { - return false; - } - cx.typeck_results().expr_ty_opt(cursor).is_some_and(|ty| ty.peel_refs().is_floating_point()) - } - fn eq_ne_suggestion<'a>( cx: &LateContext<'a>, cmp: &'a hir::Expr<'a>, @@ -303,14 +264,6 @@ fn lint_nan<'tcx>( value_span.shrink_to_hi().to(nan_span) }; - if can_suggest_is_nan_method(cx, value) { - return InvalidNanComparisonsSuggestion::Spanful { - neg: is_ne.then(|| value_span.shrink_to_lo()), - float: value_span.shrink_to_hi(), - nan_plus_binop: remove_nan, - }; - } - let Some(mut ty) = cx.typeck_results().expr_ty_opt(value) else { return InvalidNanComparisonsSuggestion::Spanless; }; diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed index 39d2ba3e93788..857ccf152fb4e 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed @@ -5,39 +5,39 @@ fn main() { let x = 5f16; - let _ = x.is_nan(); + let _ = f16::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); + let _ = !f16::is_nan(x); //~^ WARN incorrect NaN comparison let x = 5f32; - let _ = x.is_nan(); + let _ = f32::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); + let _ = !f32::is_nan(x); //~^ WARN incorrect NaN comparison let x = 5f64; - let _ = x.is_nan(); + let _ = f64::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); + let _ = !f64::is_nan(x); //~^ WARN incorrect NaN comparison let x = 5f128; - let _ = x.is_nan(); + let _ = f128::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !x.is_nan(); + let _ = !f128::is_nan(x); //~^ WARN incorrect NaN comparison let b = &2.3f32; - if !b.is_nan() {} + if !f32::is_nan(*b) {} //~^ WARN incorrect NaN comparison let b = &2.3f32; - if !b.is_nan() {} + if !f32::is_nan(*b) {} //~^ WARN incorrect NaN comparison let _ = - !b.is_nan(); + !f32::is_nan(*b); // Issue #164143: an unsuffixed float is constrained by the `NAN` operand. // Suggesting `.is_nan()` drops that constraint and does not compile. @@ -52,6 +52,22 @@ fn main() { } let _ = m; + let unary = &(-3.3); + if !f64::is_nan(*unary) {} + //~^ WARN incorrect NaN comparison + + let block = &{ 3.3 }; + if !f64::is_nan(*block) {} + //~^ WARN incorrect NaN comparison + + let (tuple,) = (&3.3,); + if !f64::is_nan(*tuple) {} + //~^ WARN incorrect NaN comparison + + let arithmetic = &(3.3 + 0.0); + if !f64::is_nan(*arithmetic) {} + //~^ WARN incorrect NaN comparison + let _ = f64::is_nan(3.3); //~^ WARN incorrect NaN comparison @@ -60,33 +76,33 @@ fn main() { let suffixed = 3.3f64; let copied = suffixed; - let _ = !copied.is_nan(); + let _ = !f64::is_nan(copied); //~^ WARN incorrect NaN comparison let ascribed: f64 = 3.3; - let _ = !ascribed.is_nan(); + let _ = !f64::is_nan(ascribed); //~^ WARN incorrect NaN comparison parameter(1.0); parameter_ref(&1.0); - let _ = |x: f64| !x.is_nan(); //~ WARN incorrect NaN comparison + let _ = |x: f64| !f64::is_nan(x); //~ WARN incorrect NaN comparison #[allow(unused_macros)] macro_rules! nan { () => { f32::NAN }; } macro_rules! number { () => { 5f32 }; } - let _ = number!().is_nan(); + let _ = f32::is_nan(number!()); //~^ WARN incorrect NaN comparison - let _ = !number!().is_nan(); + let _ = !f32::is_nan(number!()); //~^ WARN incorrect NaN comparison } fn parameter(x: f64) { - let _ = x.is_nan(); + let _ = f64::is_nan(x); //~^ WARN incorrect NaN comparison } fn parameter_ref(x: &f32) { - if !x.is_nan() {} + if !f32::is_nan(*x) {} //~^ WARN incorrect NaN comparison } diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.rs b/tests/ui/lint/invalid-nan-comparison-suggestion.rs index 18e4a4093d10f..44979955c444e 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.rs +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.rs @@ -55,6 +55,22 @@ fn main() { } let _ = m; + let unary = &(-3.3); + if unary != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let block = &{ 3.3 }; + if block != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let (tuple,) = (&3.3,); + if tuple != &f64::NAN {} + //~^ WARN incorrect NaN comparison + + let arithmetic = &(3.3 + 0.0); + if arithmetic != &f64::NAN {} + //~^ WARN incorrect NaN comparison + let _ = 3.3 == f64::NAN; //~^ WARN incorrect NaN comparison diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr index 5252977148e09..1b58a4e97a97a 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr @@ -8,7 +8,7 @@ LL | let _ = x == f16::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x == f16::NAN; -LL + let _ = x.is_nan(); +LL + let _ = f16::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -20,7 +20,7 @@ LL | let _ = x != f16::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x != f16::NAN; -LL + let _ = !x.is_nan(); +LL + let _ = !f16::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -32,7 +32,7 @@ LL | let _ = x == f32::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x == f32::NAN; -LL + let _ = x.is_nan(); +LL + let _ = f32::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -44,7 +44,7 @@ LL | let _ = x != f32::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x != f32::NAN; -LL + let _ = !x.is_nan(); +LL + let _ = !f32::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -56,7 +56,7 @@ LL | let _ = x == f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x == f64::NAN; -LL + let _ = x.is_nan(); +LL + let _ = f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -68,7 +68,7 @@ LL | let _ = x != f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x != f64::NAN; -LL + let _ = !x.is_nan(); +LL + let _ = !f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -80,7 +80,7 @@ LL | let _ = x == f128::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x == f128::NAN; -LL + let _ = x.is_nan(); +LL + let _ = f128::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -92,7 +92,7 @@ LL | let _ = x != f128::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x != f128::NAN; -LL + let _ = !x.is_nan(); +LL + let _ = !f128::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -104,7 +104,7 @@ LL | if b != &f32::NAN {} help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - if b != &f32::NAN {} -LL + if !b.is_nan() {} +LL + if !f32::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -116,7 +116,7 @@ LL | if b != { &f32::NAN } {} help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - if b != { &f32::NAN } {} -LL + if !b.is_nan() {} +LL + if !f32::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -134,7 +134,7 @@ LL - b != { LL - LL - &f32::NAN LL - }; -LL + !b.is_nan(); +LL + !f32::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -162,7 +162,55 @@ LL + if !f64::is_nan(*m) { | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:58:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:59:8 + | +LL | if unary != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if unary != &f64::NAN {} +LL + if !f64::is_nan(*unary) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:63:8 + | +LL | if block != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if block != &f64::NAN {} +LL + if !f64::is_nan(*block) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:67:8 + | +LL | if tuple != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if tuple != &f64::NAN {} +LL + if !f64::is_nan(*tuple) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:71:8 + | +LL | if arithmetic != &f64::NAN {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if arithmetic != &f64::NAN {} +LL + if !f64::is_nan(*arithmetic) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:74:13 | LL | let _ = 3.3 == f64::NAN; | ^^^^^^^^^^^^^^^ @@ -174,7 +222,7 @@ LL + let _ = f64::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:61:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:77:13 | LL | let _ = &3.3 != &f64::NAN; | ^^^^^^^^^^^^^^^^^ @@ -186,7 +234,7 @@ LL + let _ = !f64::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:66:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:82:13 | LL | let _ = copied != f64::NAN; | ^^^^^^^^^^^^^^^^^^ @@ -194,11 +242,11 @@ LL | let _ = copied != f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = copied != f64::NAN; -LL + let _ = !copied.is_nan(); +LL + let _ = !f64::is_nan(copied); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:70:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:86:13 | LL | let _ = ascribed != f64::NAN; | ^^^^^^^^^^^^^^^^^^^^ @@ -206,11 +254,11 @@ LL | let _ = ascribed != f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = ascribed != f64::NAN; -LL + let _ = !ascribed.is_nan(); +LL + let _ = !f64::is_nan(ascribed); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:75:22 + --> $DIR/invalid-nan-comparison-suggestion.rs:91:22 | LL | let _ = |x: f64| x != f64::NAN; | ^^^^^^^^^^^^^ @@ -218,11 +266,11 @@ LL | let _ = |x: f64| x != f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = |x: f64| x != f64::NAN; -LL + let _ = |x: f64| !x.is_nan(); +LL + let _ = |x: f64| !f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:81:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:97:13 | LL | let _ = nan!() == number!(); | ^^^^^^^^^^^^^^^^^^^ @@ -230,11 +278,11 @@ LL | let _ = nan!() == number!(); help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = nan!() == number!(); -LL + let _ = number!().is_nan(); +LL + let _ = f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:83:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:99:13 | LL | let _ = number!() != nan!(); | ^^^^^^^^^^^^^^^^^^^ @@ -242,11 +290,11 @@ LL | let _ = number!() != nan!(); help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = number!() != nan!(); -LL + let _ = !number!().is_nan(); +LL + let _ = !f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:88:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:104:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ @@ -254,11 +302,11 @@ LL | let _ = x == f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - let _ = x == f64::NAN; -LL + let _ = x.is_nan(); +LL + let _ = f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:93:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:109:8 | LL | if x != &f32::NAN {} | ^^^^^^^^^^^^^^ @@ -266,8 +314,8 @@ LL | if x != &f32::NAN {} help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - if x != &f32::NAN {} -LL + if !x.is_nan() {} +LL + if !f32::is_nan(*x) {} | -warning: 22 warnings emitted +warning: 26 warnings emitted diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr index 486d2a9636c95..4b31abf84ff54 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparison.stderr @@ -8,7 +8,7 @@ LL | const TEST: bool = 5f32 == f32::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - const TEST: bool = 5f32 == f32::NAN; -LL + const TEST: bool = 5f32.is_nan(); +LL + const TEST: bool = f32::is_nan(5f32); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -20,7 +20,7 @@ LL | x == f16::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x == f16::NAN; -LL + x.is_nan(); +LL + f16::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -32,7 +32,7 @@ LL | x != f16::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x != f16::NAN; -LL + !x.is_nan(); +LL + !f16::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -68,7 +68,7 @@ LL | number!() == f16::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - number!() == f16::NAN; -LL + number!().is_nan(); +LL + f16::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -80,7 +80,7 @@ LL | f16::NAN != number!(); help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - f16::NAN != number!(); -LL + !number!().is_nan(); +LL + !f16::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -92,7 +92,7 @@ LL | x == f32::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x == f32::NAN; -LL + x.is_nan(); +LL + f32::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -104,7 +104,7 @@ LL | x != f32::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x != f32::NAN; -LL + !x.is_nan(); +LL + !f32::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -140,7 +140,7 @@ LL | number!() == f32::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - number!() == f32::NAN; -LL + number!().is_nan(); +LL + f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -152,7 +152,7 @@ LL | f32::NAN != number!(); help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - f32::NAN != number!(); -LL + !number!().is_nan(); +LL + !f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -164,7 +164,7 @@ LL | x == f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x == f64::NAN; -LL + x.is_nan(); +LL + f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -176,7 +176,7 @@ LL | x != f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x != f64::NAN; -LL + !x.is_nan(); +LL + !f64::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -212,7 +212,7 @@ LL | number!() == f64::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - number!() == f64::NAN; -LL + number!().is_nan(); +LL + f64::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -224,7 +224,7 @@ LL | f64::NAN != number!(); help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - f64::NAN != number!(); -LL + !number!().is_nan(); +LL + !f64::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -236,7 +236,7 @@ LL | x == f128::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x == f128::NAN; -LL + x.is_nan(); +LL + f128::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -248,7 +248,7 @@ LL | x != f128::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - x != f128::NAN; -LL + !x.is_nan(); +LL + !f128::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -284,7 +284,7 @@ LL | number!() == f128::NAN; help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - number!() == f128::NAN; -LL + number!().is_nan(); +LL + f128::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -296,7 +296,7 @@ LL | f128::NAN != number!(); help: use `f32::is_nan()` or `f64::is_nan()` instead | LL - f128::NAN != number!(); -LL + !number!().is_nan(); +LL + !f128::is_nan(number!()); | warning: 33 warnings emitted From ed4718fea5784a076c587b7467737d4e9bf8d133 Mon Sep 17 00:00:00 2001 From: Yu Date: Wed, 14 Oct 2026 01:19:39 +0800 Subject: [PATCH 04/14] lint: preserve qualified paths in NaN suggestions --- compiler/rustc_lint/src/types.rs | 13 +- .../invalid-nan-comparison-suggestion.fixed | 28 +++++ .../lint/invalid-nan-comparison-suggestion.rs | 28 +++++ .../invalid-nan-comparison-suggestion.stderr | 114 +++++++++++++----- 4 files changed, 155 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 4769cb7bf485c..78cf3429116ec 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -245,6 +245,14 @@ fn lint_nan<'tcx>( } } + fn nan_method_path(cx: &LateContext<'_>, nan: &hir::Expr<'_>) -> Option { + let expr = nan.peel_blocks().peel_borrows(); + let path = cx.sess().source_map().span_to_snippet(expr.span).ok()?; + path.strip_suffix("NAN") + .filter(|path| path.contains("::")) + .map(|path| format!("{path}is_nan")) + } + fn eq_ne_suggestion<'a>( cx: &LateContext<'a>, cmp: &'a hir::Expr<'a>, @@ -295,8 +303,11 @@ fn lint_nan<'tcx>( } let written_borrow = outer_span.until(operand_span); let neg = if is_ne { "!" } else { "" }; + let Some(method_path) = nan_method_path(cx, nan) else { + return InvalidNanComparisonsSuggestion::Spanless; + }; InvalidNanComparisonsSuggestion::Ufcs { - prefix: format!("{neg}{}::is_nan({}", float_ty.name_str(), "*".repeat(deref_count)), + prefix: format!("{neg}{method_path}({}", "*".repeat(deref_count)), prefix_span: operand_span.shrink_to_lo(), close_span: operand_span.shrink_to_hi(), remove_nan, diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed index 857ccf152fb4e..8fbdd079053c2 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed @@ -3,6 +3,8 @@ #![feature(f16, f128)] +extern crate core; + fn main() { let x = 5f16; let _ = f16::is_nan(x); @@ -68,6 +70,17 @@ fn main() { if !f64::is_nan(*arithmetic) {} //~^ WARN incorrect NaN comparison + let x = 1.0f64; + if !f64::is_nan(x) {} + //~^ WARN incorrect NaN comparison + let p = &x; + let _ = f64::is_nan(*p); + //~^ WARN incorrect NaN comparison + let _ = f64::is_nan(-x); + //~^ WARN incorrect NaN comparison + + shadowed::check(); + let _ = f64::is_nan(3.3); //~^ WARN incorrect NaN comparison @@ -106,3 +119,18 @@ fn parameter_ref(x: &f32) { if !f32::is_nan(*x) {} //~^ WARN incorrect NaN comparison } + +mod shadowed { + #[allow(dead_code, non_camel_case_types)] + struct f64; + use ::core::primitive::f64 as Float; + + pub fn check() { + let b = &3.3; + if !::core::primitive::f64::is_nan(*b) {} + //~^ WARN incorrect NaN comparison + let c = &4.4; + if !Float::is_nan(*c) {} + //~^ WARN incorrect NaN comparison + } +} diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.rs b/tests/ui/lint/invalid-nan-comparison-suggestion.rs index 44979955c444e..fb23208dfcfc9 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.rs +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.rs @@ -3,6 +3,8 @@ #![feature(f16, f128)] +extern crate core; + fn main() { let x = 5f16; let _ = x == f16::NAN; @@ -71,6 +73,17 @@ fn main() { if arithmetic != &f64::NAN {} //~^ WARN incorrect NaN comparison + let x = 1.0f64; + if &x != &f64::NAN {} + //~^ WARN incorrect NaN comparison + let p = &x; + let _ = *p == f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = -x == f64::NAN; + //~^ WARN incorrect NaN comparison + + shadowed::check(); + let _ = 3.3 == f64::NAN; //~^ WARN incorrect NaN comparison @@ -109,3 +122,18 @@ fn parameter_ref(x: &f32) { if x != &f32::NAN {} //~^ WARN incorrect NaN comparison } + +mod shadowed { + #[allow(dead_code, non_camel_case_types)] + struct f64; + use ::core::primitive::f64 as Float; + + pub fn check() { + let b = &3.3; + if b != &::core::primitive::f64::NAN {} + //~^ WARN incorrect NaN comparison + let c = &4.4; + if c != &Float::NAN {} + //~^ WARN incorrect NaN comparison + } +} diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr index 1b58a4e97a97a..c9f3b6bd95052 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr @@ -1,5 +1,5 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:8:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:10:13 | LL | let _ = x == f16::NAN; | ^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + let _ = f16::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:10:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:12:13 | LL | let _ = x != f16::NAN; | ^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + let _ = !f16::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:14:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:16:13 | LL | let _ = x == f32::NAN; | ^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + let _ = f32::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:16:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:18:13 | LL | let _ = x != f32::NAN; | ^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + let _ = !f32::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:20:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:22:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + let _ = f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:22:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:24:13 | LL | let _ = x != f64::NAN; | ^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL + let _ = !f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:26:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:28:13 | LL | let _ = x == f128::NAN; | ^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL + let _ = f128::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:28:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:30:13 | LL | let _ = x != f128::NAN; | ^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + let _ = !f128::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:32:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:34:8 | LL | if b != &f32::NAN {} | ^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + if !f32::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:36:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:38:8 | LL | if b != { &f32::NAN } {} | ^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + if !f32::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:40:9 + --> $DIR/invalid-nan-comparison-suggestion.rs:42:9 | LL | / b != { LL | | @@ -138,7 +138,7 @@ LL + !f32::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:48:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:50:8 | LL | if b != &f64::NAN {} | ^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL + if !f64::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:52:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:54:8 | LL | if m != &f64::NAN { | ^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL + if !f64::is_nan(*m) { | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:59:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:61:8 | LL | if unary != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ LL + if !f64::is_nan(*unary) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:63:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:65:8 | LL | if block != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -186,7 +186,7 @@ LL + if !f64::is_nan(*block) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:67:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:69:8 | LL | if tuple != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL + if !f64::is_nan(*tuple) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:71:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:73:8 | LL | if arithmetic != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +210,43 @@ LL + if !f64::is_nan(*arithmetic) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:74:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:77:8 + | +LL | if &x != &f64::NAN {} + | ^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if &x != &f64::NAN {} +LL + if !f64::is_nan(x) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:80:13 + | +LL | let _ = *p == f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = *p == f64::NAN; +LL + let _ = f64::is_nan(*p); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:82:13 + | +LL | let _ = -x == f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - let _ = -x == f64::NAN; +LL + let _ = f64::is_nan(-x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:87:13 | LL | let _ = 3.3 == f64::NAN; | ^^^^^^^^^^^^^^^ @@ -222,7 +258,7 @@ LL + let _ = f64::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:77:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:90:13 | LL | let _ = &3.3 != &f64::NAN; | ^^^^^^^^^^^^^^^^^ @@ -234,7 +270,7 @@ LL + let _ = !f64::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:82:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:95:13 | LL | let _ = copied != f64::NAN; | ^^^^^^^^^^^^^^^^^^ @@ -246,7 +282,7 @@ LL + let _ = !f64::is_nan(copied); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:86:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:99:13 | LL | let _ = ascribed != f64::NAN; | ^^^^^^^^^^^^^^^^^^^^ @@ -258,7 +294,7 @@ LL + let _ = !f64::is_nan(ascribed); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:91:22 + --> $DIR/invalid-nan-comparison-suggestion.rs:104:22 | LL | let _ = |x: f64| x != f64::NAN; | ^^^^^^^^^^^^^ @@ -270,7 +306,7 @@ LL + let _ = |x: f64| !f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:97:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:110:13 | LL | let _ = nan!() == number!(); | ^^^^^^^^^^^^^^^^^^^ @@ -282,7 +318,7 @@ LL + let _ = f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:99:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:112:13 | LL | let _ = number!() != nan!(); | ^^^^^^^^^^^^^^^^^^^ @@ -294,7 +330,7 @@ LL + let _ = !f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:104:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:117:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ @@ -306,7 +342,7 @@ LL + let _ = f64::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:109:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:122:8 | LL | if x != &f32::NAN {} | ^^^^^^^^^^^^^^ @@ -317,5 +353,29 @@ LL - if x != &f32::NAN {} LL + if !f32::is_nan(*x) {} | -warning: 26 warnings emitted +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:133:12 + | +LL | if b != &::core::primitive::f64::NAN {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if b != &::core::primitive::f64::NAN {} +LL + if !::core::primitive::f64::is_nan(*b) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:136:12 + | +LL | if c != &Float::NAN {} + | ^^^^^^^^^^^^^^^^ + | +help: use `f32::is_nan()` or `f64::is_nan()` instead + | +LL - if c != &Float::NAN {} +LL + if !Float::is_nan(*c) {} + | + +warning: 31 warnings emitted From 62cf356902c44a2c2362b02b901831d4c8dd9b40 Mon Sep 17 00:00:00 2001 From: Yu Date: Wed, 14 Oct 2026 14:05:14 +0800 Subject: [PATCH 05/14] lint: fix NaN suggestions for nested operands and macros --- compiler/rustc_lint/src/diagnostics.rs | 9 +- compiler/rustc_lint/src/types.rs | 118 ++++--- ...nvalid-nan-comparison-custom-partial-eq.rs | 25 ++ ...id-nan-comparison-custom-partial-eq.stderr | 27 ++ .../lint/invalid-nan-comparison-no-std.fixed | 18 ++ .../ui/lint/invalid-nan-comparison-no-std.rs | 18 ++ .../lint/invalid-nan-comparison-no-std.stderr | 15 + .../invalid-nan-comparison-no-suggestion.rs | 28 ++ ...nvalid-nan-comparison-no-suggestion.stderr | 50 +++ .../invalid-nan-comparison-suggestion.fixed | 113 +++++-- .../lint/invalid-nan-comparison-suggestion.rs | 51 +++ .../invalid-nan-comparison-suggestion.stderr | 304 +++++++++++++----- tests/ui/lint/invalid-nan-comparison.stderr | 68 ++-- 13 files changed, 649 insertions(+), 195 deletions(-) create mode 100644 tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs create mode 100644 tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr create mode 100644 tests/ui/lint/invalid-nan-comparison-no-std.fixed create mode 100644 tests/ui/lint/invalid-nan-comparison-no-std.rs create mode 100644 tests/ui/lint/invalid-nan-comparison-no-std.stderr create mode 100644 tests/ui/lint/invalid-nan-comparison-no-suggestion.rs create mode 100644 tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index ea36a485fc3ac..d66a3c1ca13f3 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -2322,7 +2322,7 @@ pub(crate) enum InvalidNanComparisons { #[derive(Subdiagnostic)] pub(crate) enum InvalidNanComparisonsSuggestion { #[multipart_suggestion( - "use `f32::is_nan()` or `f64::is_nan()` instead", + "use the `is_nan` method instead", style = "verbose", applicability = "machine-applicable" )] @@ -2330,14 +2330,13 @@ pub(crate) enum InvalidNanComparisonsSuggestion { prefix: String, #[suggestion_part(code = "{prefix}")] prefix_span: Span, - #[suggestion_part(code = ")")] + suffix: &'static str, + #[suggestion_part(code = "{suffix}")] close_span: Span, #[suggestion_part(code = "")] remove_nan: Span, - #[suggestion_part(code = "")] - remove_borrow: Option, }, - #[help("use `f32::is_nan()` or `f64::is_nan()` instead")] + #[help("use the `is_nan` method instead")] Spanless, } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 78cf3429116ec..c38e77c5fe6c7 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -2,6 +2,7 @@ use std::iter; use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange}; use rustc_ast as ast; +use rustc_ast::util::parser::ExprPrecedence; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; use rustc_hir as hir; @@ -113,8 +114,8 @@ declare_lint! { } declare_lint! { - /// The `invalid_nan_comparisons` lint checks comparison with `f32::NAN` or `f64::NAN` - /// as one of the operand. + /// The `invalid_nan_comparisons` lint checks comparisons with the `NAN` constants + /// of `f16`, `f32`, `f64`, and `f128`. /// /// ### Example /// @@ -127,8 +128,8 @@ declare_lint! { /// /// ### Explanation /// - /// NaN does not compare meaningfully to anything – not - /// even itself – so those comparisons are always false. + /// NaN compares unequal to every floating-point value, including itself. + /// Use the `is_nan` method to check whether a value is NaN. INVALID_NAN_COMPARISONS, Warn, "detects invalid floating point NaN comparisons" @@ -229,28 +230,50 @@ fn lint_nan<'tcx>( l: &'tcx hir::Expr<'tcx>, r: &'tcx hir::Expr<'tcx>, ) { - fn nan_ty(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { - let expr = expr.peel_blocks().peel_borrows(); + fn nan_ty(cx: &LateContext<'_>, mut expr: &hir::Expr<'_>) -> Option { + loop { + expr = expr.peel_blocks(); + match expr.kind { + ExprKind::AddrOf(.., inner) => expr = inner, + _ => break, + } + } let ExprKind::Path(qpath) = expr.kind else { return None }; let def_id = cx.typeck_results().qpath_res(&qpath, expr.hir_id).opt_def_id()?; - if !matches!( - cx.tcx.get_diagnostic_name(def_id), - Some(sym::f16_nan | sym::f32_nan | sym::f64_nan | sym::f128_nan) - ) { - return None; - } - match cx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() { - ty::Float(fty) => Some(*fty), - _ => None, - } + Some(match cx.tcx.get_diagnostic_name(def_id)? { + sym::f16_nan => ty::FloatTy::F16, + sym::f32_nan => ty::FloatTy::F32, + sym::f64_nan => ty::FloatTy::F64, + sym::f128_nan => ty::FloatTy::F128, + _ => return None, + }) } - fn nan_method_path(cx: &LateContext<'_>, nan: &hir::Expr<'_>) -> Option { - let expr = nan.peel_blocks().peel_borrows(); - let path = cx.sess().source_map().span_to_snippet(expr.span).ok()?; - path.strip_suffix("NAN") - .filter(|path| path.contains("::")) - .map(|path| format!("{path}is_nan")) + fn nan_method_path( + cx: &LateContext<'_>, + mut nan: &hir::Expr<'_>, + float_ty: ty::FloatTy, + cmp_span: Span, + ) -> Option { + loop { + match nan.kind { + ExprKind::AddrOf(.., inner) => nan = inner, + ExprKind::Block(block, _) if block.stmts.is_empty() => nan = block.expr?, + _ => break, + } + } + let ExprKind::Path(hir::QPath::TypeRelative(ty, _)) = nan.kind else { + return None; + }; + if !ty.span.from_expansion() && cmp_span.contains(ty.span) { + let ty = cx.sess().source_map().span_to_snippet(ty.span).ok()?; + Some(format!("<{ty}>::is_nan")) + } else if matches!(float_ty, ty::FloatTy::F32 | ty::FloatTy::F64) { + let krate = std_or_core(cx)?; + Some(format!("::{krate}::primitive::{}::is_nan", float_ty.name_str())) + } else { + None + } } fn eq_ne_suggestion<'a>( @@ -261,11 +284,18 @@ fn lint_nan<'tcx>( float_ty: ty::FloatTy, is_ne: bool, ) -> InvalidNanComparisonsSuggestion { - let (Some(value_span), Some(nan_span)) = - (value.span.find_ancestor_inside(cmp.span), nan.span.find_ancestor_inside(cmp.span)) - else { + if cmp.span.from_expansion() { + return InvalidNanComparisonsSuggestion::Spanless; + } + let (Some(value_span), Some(nan_span)) = ( + value.span.find_ancestor_inside_same_ctxt(cmp.span), + nan.span.find_ancestor_inside_same_ctxt(cmp.span), + ) else { return InvalidNanComparisonsSuggestion::Spanless; }; + if value_span.overlaps(nan_span) { + return InvalidNanComparisonsSuggestion::Spanless; + } let remove_nan = if nan_span.lo() < value_span.lo() { nan_span.until(value_span) } else { @@ -275,43 +305,29 @@ fn lint_nan<'tcx>( let Some(mut ty) = cx.typeck_results().expr_ty_opt(value) else { return InvalidNanComparisonsSuggestion::Spanless; }; - let mut operand = value.peel_blocks(); - let Some(mut operand_span) = operand.span.find_ancestor_inside(value_span) else { - return InvalidNanComparisonsSuggestion::Spanless; - }; - let outer_span = operand_span; let mut deref_count = 0; while let ty::Ref(_, inner, _) = *ty.kind() { - if let ExprKind::AddrOf(_, _, inner_expr) = operand.kind - && let peeled = inner_expr.peel_blocks() - && let Some(peeled_span) = peeled.span.find_ancestor_inside(operand_span) - { - operand = peeled; - operand_span = peeled_span; - } else { - deref_count += 1; - } + deref_count += 1; ty = inner; } - let matches_float = match *ty.kind() { - ty::Float(fty) => fty == float_ty, - ty::Infer(ty::FloatVar(_)) => true, - _ => false, - }; - if !matches_float { + if !matches!(*ty.kind(), ty::Float(fty) if fty == float_ty) { return InvalidNanComparisonsSuggestion::Spanless; } - let written_borrow = outer_span.until(operand_span); let neg = if is_ne { "!" } else { "" }; - let Some(method_path) = nan_method_path(cx, nan) else { + let Some(method_path) = nan_method_path(cx, nan, float_ty, cmp.span) else { return InvalidNanComparisonsSuggestion::Spanless; }; + let (open, suffix) = if deref_count != 0 && cx.precedence(value) < ExprPrecedence::Prefix { + ("(", "))") + } else { + ("", ")") + }; InvalidNanComparisonsSuggestion::Ufcs { - prefix: format!("{neg}{method_path}({}", "*".repeat(deref_count)), - prefix_span: operand_span.shrink_to_lo(), - close_span: operand_span.shrink_to_hi(), + prefix: format!("{neg}{method_path}({}{open}", "*".repeat(deref_count)), + prefix_span: value_span.shrink_to_lo(), + suffix, + close_span: value_span.shrink_to_hi(), remove_nan, - remove_borrow: (!written_borrow.is_empty()).then_some(written_borrow), } } diff --git a/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs b/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs new file mode 100644 index 0000000000000..be3351916ddc4 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs @@ -0,0 +1,25 @@ +//@ check-pass + +struct NotFloat; + +impl PartialEq for NotFloat { + fn eq(&self, _: &f64) -> bool { + true + } +} + +impl PartialEq for f64 { + fn eq(&self, _: &NotFloat) -> bool { + true + } +} + +fn main() { + let value = NotFloat; + let _ = value == f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = f64::NAN != value; + //~^ WARN incorrect NaN comparison + let _ = &value != &f64::NAN; + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr b/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr new file mode 100644 index 0000000000000..daf91b092a3bb --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr @@ -0,0 +1,27 @@ +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-custom-partial-eq.rs:19:13 + | +LL | let _ = value == f64::NAN; + | ^^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + = note: `#[warn(invalid_nan_comparisons)]` on by default + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-custom-partial-eq.rs:21:13 + | +LL | let _ = f64::NAN != value; + | ^^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-custom-partial-eq.rs:23:13 + | +LL | let _ = &value != &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: 3 warnings emitted + diff --git a/tests/ui/lint/invalid-nan-comparison-no-std.fixed b/tests/ui/lint/invalid-nan-comparison-no-std.fixed new file mode 100644 index 0000000000000..3e35d14d223d7 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-no-std.fixed @@ -0,0 +1,18 @@ +//@ check-pass +//@ run-rustfix +//@ compile-flags: --crate-type=lib + +#![no_std] + +pub type MacroFloat = ::core::primitive::f64; + +#[allow(non_camel_case_types)] +pub struct f64; + +pub fn check() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = !::core::primitive::f64::is_nan(*b); + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparison-no-std.rs b/tests/ui/lint/invalid-nan-comparison-no-std.rs new file mode 100644 index 0000000000000..7ace5b976c890 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-no-std.rs @@ -0,0 +1,18 @@ +//@ check-pass +//@ run-rustfix +//@ compile-flags: --crate-type=lib + +#![no_std] + +pub type MacroFloat = ::core::primitive::f64; + +#[allow(non_camel_case_types)] +pub struct f64; + +pub fn check() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = b != &nan!(); + //~^ WARN incorrect NaN comparison +} diff --git a/tests/ui/lint/invalid-nan-comparison-no-std.stderr b/tests/ui/lint/invalid-nan-comparison-no-std.stderr new file mode 100644 index 0000000000000..143736b352ad9 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-no-std.stderr @@ -0,0 +1,15 @@ +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-no-std.rs:16:13 + | +LL | let _ = b != &nan!(); + | ^^^^^^^^^^^^ + | + = note: `#[warn(invalid_nan_comparisons)]` on by default +help: use the `is_nan` method instead + | +LL - let _ = b != &nan!(); +LL + let _ = !::core::primitive::f64::is_nan(*b); + | + +warning: 1 warning emitted + diff --git a/tests/ui/lint/invalid-nan-comparison-no-suggestion.rs b/tests/ui/lint/invalid-nan-comparison-no-suggestion.rs new file mode 100644 index 0000000000000..afe3cb7cfd259 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-no-suggestion.rs @@ -0,0 +1,28 @@ +//@ check-pass + +#![feature(f16, f128)] + +fn main() { + let mut effects = 0; + let _ = 3.3 == { + effects += 1; + f64::NAN + }; + //~^^^^ WARN incorrect NaN comparison + let _ = effects; + + macro_rules! scoped_nan { () => {{ type Float = f64; Float::NAN }}; } + let _ = 3.3 == scoped_nan!(); + //~^ WARN incorrect NaN comparison + + macro_rules! nan16 { () => { f16::NAN }; } + let _ = 3.3 == nan16!(); + //~^ WARN incorrect NaN comparison + macro_rules! nan128 { () => { f128::NAN }; } + let _ = 3.3 != nan128!(); + //~^ WARN incorrect NaN comparison + + macro_rules! compare { () => { 3.3 != f64::NAN }; } + //~^ WARN incorrect NaN comparison + let _ = compare!(); +} diff --git a/tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr new file mode 100644 index 0000000000000..659deb868b027 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr @@ -0,0 +1,50 @@ +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-no-suggestion.rs:7:13 + | +LL | let _ = 3.3 == { + | _____________^ +LL | | effects += 1; +LL | | f64::NAN +LL | | }; + | |_____^ + | + = help: use the `is_nan` method instead + = note: `#[warn(invalid_nan_comparisons)]` on by default + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-no-suggestion.rs:15:13 + | +LL | let _ = 3.3 == scoped_nan!(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-no-suggestion.rs:19:13 + | +LL | let _ = 3.3 == nan16!(); + | ^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-no-suggestion.rs:22:13 + | +LL | let _ = 3.3 != nan128!(); + | ^^^^^^^^^^^^^^^^ + | + = help: use the `is_nan` method instead + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-no-suggestion.rs:25:36 + | +LL | macro_rules! compare { () => { 3.3 != f64::NAN }; } + | ^^^^^^^^^^^^^^^ +LL | +LL | let _ = compare!(); + | ---------- in this macro invocation + | + = help: use the `is_nan` method instead + +warning: 5 warnings emitted + diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed index 8fbdd079053c2..d3043e3f72516 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.fixed @@ -7,116 +7,164 @@ extern crate core; fn main() { let x = 5f16; - let _ = f16::is_nan(x); + let _ = ::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !f16::is_nan(x); + let _ = !::is_nan(x); //~^ WARN incorrect NaN comparison let x = 5f32; - let _ = f32::is_nan(x); + let _ = ::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !f32::is_nan(x); + let _ = !::is_nan(x); //~^ WARN incorrect NaN comparison let x = 5f64; - let _ = f64::is_nan(x); + let _ = ::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !f64::is_nan(x); + let _ = !::is_nan(x); //~^ WARN incorrect NaN comparison let x = 5f128; - let _ = f128::is_nan(x); + let _ = ::is_nan(x); //~^ WARN incorrect NaN comparison - let _ = !f128::is_nan(x); + let _ = !::is_nan(x); //~^ WARN incorrect NaN comparison let b = &2.3f32; - if !f32::is_nan(*b) {} + if !::is_nan(*b) {} //~^ WARN incorrect NaN comparison let b = &2.3f32; - if !f32::is_nan(*b) {} + if !::is_nan(*b) {} //~^ WARN incorrect NaN comparison let _ = - !f32::is_nan(*b); + !::is_nan(*b); // Issue #164143: an unsuffixed float is constrained by the `NAN` operand. // Suggesting `.is_nan()` drops that constraint and does not compile. let b = &3.3; - if !f64::is_nan(*b) {} + if !::is_nan(*b) {} //~^ WARN incorrect NaN comparison let mut m = &3.3; - if !f64::is_nan(*m) { + if !::is_nan(*m) { //~^ WARN incorrect NaN comparison m = &1.0; } let _ = m; let unary = &(-3.3); - if !f64::is_nan(*unary) {} + if !::is_nan(*unary) {} //~^ WARN incorrect NaN comparison let block = &{ 3.3 }; - if !f64::is_nan(*block) {} + if !::is_nan(*block) {} //~^ WARN incorrect NaN comparison let (tuple,) = (&3.3,); - if !f64::is_nan(*tuple) {} + if !::is_nan(*tuple) {} //~^ WARN incorrect NaN comparison let arithmetic = &(3.3 + 0.0); - if !f64::is_nan(*arithmetic) {} + if !::is_nan(*arithmetic) {} //~^ WARN incorrect NaN comparison let x = 1.0f64; - if !f64::is_nan(x) {} + if !::is_nan(*&x) {} //~^ WARN incorrect NaN comparison let p = &x; - let _ = f64::is_nan(*p); + let _ = ::is_nan(*p); //~^ WARN incorrect NaN comparison - let _ = f64::is_nan(-x); + let _ = ::is_nan(-x); //~^ WARN incorrect NaN comparison shadowed::check(); + nested_operands(); + macro_paths(); - let _ = f64::is_nan(3.3); + let _ = ::is_nan(3.3); //~^ WARN incorrect NaN comparison - let _ = !f64::is_nan(3.3); + let _ = !::is_nan(*&3.3); //~^ WARN incorrect NaN comparison let suffixed = 3.3f64; let copied = suffixed; - let _ = !f64::is_nan(copied); + let _ = !::is_nan(copied); //~^ WARN incorrect NaN comparison let ascribed: f64 = 3.3; - let _ = !f64::is_nan(ascribed); + let _ = !::is_nan(ascribed); //~^ WARN incorrect NaN comparison parameter(1.0); parameter_ref(&1.0); - let _ = |x: f64| !f64::is_nan(x); //~ WARN incorrect NaN comparison + let _ = |x: f64| !::is_nan(x); //~ WARN incorrect NaN comparison #[allow(unused_macros)] macro_rules! nan { () => { f32::NAN }; } macro_rules! number { () => { 5f32 }; } - let _ = f32::is_nan(number!()); + let _ = ::std::primitive::f32::is_nan(number!()); //~^ WARN incorrect NaN comparison - let _ = !f32::is_nan(number!()); + let _ = !::std::primitive::f32::is_nan(number!()); //~^ WARN incorrect NaN comparison } fn parameter(x: f64) { - let _ = f64::is_nan(x); + let _ = ::is_nan(x); //~^ WARN incorrect NaN comparison } fn parameter_ref(x: &f32) { - if !f32::is_nan(*x) {} + if !::is_nan(*x) {} + //~^ WARN incorrect NaN comparison +} + +fn nested_operands() { + let x = 1.0f64; + let _ = ::is_nan(*(&x as &f64)); + //~^ WARN incorrect NaN comparison + let _ = !::is_nan(*{ &{ 3.3 } }); + //~^ WARN incorrect NaN comparison + let _ = ::is_nan(***&&&3.3); + //~^ WARN incorrect NaN comparison + let b = &&&3.3; + let _ = !::is_nan(***b); + //~^ WARN incorrect NaN comparison + let b = &mut 3.3; + let _ = !::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = ::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = !::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &&3.3; + let _ = ::is_nan(**b); + //~^ WARN incorrect NaN comparison + + let b = &(-3.3); + let _ = !::is_nan(*b); + //~^ WARN incorrect NaN comparison + let b = &(3.3 + 0.0); + let _ = ::is_nan(*b); + //~^ WARN incorrect NaN comparison + + macro_rules! borrowed { () => { &3.3 }; } + let _ = !::is_nan(*borrowed!()); + //~^ WARN incorrect NaN comparison +} + +pub type MacroFloat = f64; + +fn macro_paths() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = !::std::primitive::f64::is_nan(*b); //~^ WARN incorrect NaN comparison } @@ -127,10 +175,13 @@ mod shadowed { pub fn check() { let b = &3.3; - if !::core::primitive::f64::is_nan(*b) {} + if !<::core::primitive::f64>::is_nan(*b) {} //~^ WARN incorrect NaN comparison let c = &4.4; - if !Float::is_nan(*c) {} + if !::is_nan(*c) {} + //~^ WARN incorrect NaN comparison + let d = &5.5; + if !::is_nan(*d) {} //~^ WARN incorrect NaN comparison } } diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.rs b/tests/ui/lint/invalid-nan-comparison-suggestion.rs index fb23208dfcfc9..d5376db904453 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.rs +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.rs @@ -83,6 +83,8 @@ fn main() { //~^ WARN incorrect NaN comparison shadowed::check(); + nested_operands(); + macro_paths(); let _ = 3.3 == f64::NAN; //~^ WARN incorrect NaN comparison @@ -123,6 +125,52 @@ fn parameter_ref(x: &f32) { //~^ WARN incorrect NaN comparison } +fn nested_operands() { + let x = 1.0f64; + let _ = &x as &f64 == &f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = { &{ 3.3 } } != &f64::NAN; + //~^ WARN incorrect NaN comparison + let _ = &&&3.3 == &&&f64::NAN; + //~^ WARN incorrect NaN comparison + let b = &&&3.3; + let _ = &&&f64::NAN != b; + //~^ WARN incorrect NaN comparison + let b = &mut 3.3; + let _ = b != &f64::NAN; + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = &(::NAN) == b; + //~^ WARN incorrect NaN comparison + let b = &3.3; + let _ = b != &{ f64::NAN }; + //~^ WARN incorrect NaN comparison + let b = &&3.3; + let _ = &{ &{ f64::NAN } } == b; + //~^ WARN incorrect NaN comparison + + let b = &(-3.3); + let _ = b != &f16::NAN; + //~^ WARN incorrect NaN comparison + let b = &(3.3 + 0.0); + let _ = b == &f128::NAN; + //~^ WARN incorrect NaN comparison + + macro_rules! borrowed { () => { &3.3 }; } + let _ = borrowed!() != &f64::NAN; + //~^ WARN incorrect NaN comparison +} + +pub type MacroFloat = f64; + +fn macro_paths() { + #[allow(unused_macros)] + macro_rules! nan { () => { $crate::MacroFloat::NAN }; } + let b = &3.3; + let _ = b != &nan!(); + //~^ WARN incorrect NaN comparison +} + mod shadowed { #[allow(dead_code, non_camel_case_types)] struct f64; @@ -135,5 +183,8 @@ mod shadowed { let c = &4.4; if c != &Float::NAN {} //~^ WARN incorrect NaN comparison + let d = &5.5; + if d != &Float::r#NAN {} + //~^ WARN incorrect NaN comparison } } diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr index c9f3b6bd95052..9c920496c3f54 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparison-suggestion.stderr @@ -5,10 +5,10 @@ LL | let _ = x == f16::NAN; | ^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x == f16::NAN; -LL + let _ = f16::is_nan(x); +LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -17,10 +17,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x != f16::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x != f16::NAN; -LL + let _ = !f16::is_nan(x); +LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -29,10 +29,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x == f32::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x == f32::NAN; -LL + let _ = f32::is_nan(x); +LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -41,10 +41,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x != f32::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x != f32::NAN; -LL + let _ = !f32::is_nan(x); +LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -53,10 +53,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x == f64::NAN; -LL + let _ = f64::is_nan(x); +LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -65,10 +65,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x != f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x != f64::NAN; -LL + let _ = !f64::is_nan(x); +LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -77,10 +77,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x == f128::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x == f128::NAN; -LL + let _ = f128::is_nan(x); +LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -89,10 +89,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = x != f128::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x != f128::NAN; -LL + let _ = !f128::is_nan(x); +LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -101,10 +101,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if b != &f32::NAN {} | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if b != &f32::NAN {} -LL + if !f32::is_nan(*b) {} +LL + if !::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -113,10 +113,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if b != { &f32::NAN } {} | ^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if b != { &f32::NAN } {} -LL + if !f32::is_nan(*b) {} +LL + if !::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -128,13 +128,13 @@ LL | | &f32::NAN LL | | }; | |_________^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - b != { LL - LL - &f32::NAN LL - }; -LL + !f32::is_nan(*b); +LL + !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -143,10 +143,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if b != &f64::NAN {} | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if b != &f64::NAN {} -LL + if !f64::is_nan(*b) {} +LL + if !::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -155,10 +155,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if m != &f64::NAN { | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if m != &f64::NAN { -LL + if !f64::is_nan(*m) { +LL + if !::is_nan(*m) { | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -167,10 +167,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if unary != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if unary != &f64::NAN {} -LL + if !f64::is_nan(*unary) {} +LL + if !::is_nan(*unary) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -179,10 +179,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if block != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if block != &f64::NAN {} -LL + if !f64::is_nan(*block) {} +LL + if !::is_nan(*block) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -191,10 +191,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if tuple != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if tuple != &f64::NAN {} -LL + if !f64::is_nan(*tuple) {} +LL + if !::is_nan(*tuple) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -203,10 +203,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if arithmetic != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if arithmetic != &f64::NAN {} -LL + if !f64::is_nan(*arithmetic) {} +LL + if !::is_nan(*arithmetic) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -215,10 +215,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | if &x != &f64::NAN {} | ^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if &x != &f64::NAN {} -LL + if !f64::is_nan(x) {} +LL + if !::is_nan(*&x) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -227,10 +227,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = *p == f64::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = *p == f64::NAN; -LL + let _ = f64::is_nan(*p); +LL + let _ = ::is_nan(*p); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -239,143 +239,299 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | let _ = -x == f64::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = -x == f64::NAN; -LL + let _ = f64::is_nan(-x); +LL + let _ = ::is_nan(-x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:87:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:89:13 | LL | let _ = 3.3 == f64::NAN; | ^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = 3.3 == f64::NAN; -LL + let _ = f64::is_nan(3.3); +LL + let _ = ::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:90:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:92:13 | LL | let _ = &3.3 != &f64::NAN; | ^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = &3.3 != &f64::NAN; -LL + let _ = !f64::is_nan(3.3); +LL + let _ = !::is_nan(*&3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:95:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:97:13 | LL | let _ = copied != f64::NAN; | ^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = copied != f64::NAN; -LL + let _ = !f64::is_nan(copied); +LL + let _ = !::is_nan(copied); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:99:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:101:13 | LL | let _ = ascribed != f64::NAN; | ^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = ascribed != f64::NAN; -LL + let _ = !f64::is_nan(ascribed); +LL + let _ = !::is_nan(ascribed); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:104:22 + --> $DIR/invalid-nan-comparison-suggestion.rs:106:22 | LL | let _ = |x: f64| x != f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = |x: f64| x != f64::NAN; -LL + let _ = |x: f64| !f64::is_nan(x); +LL + let _ = |x: f64| !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:110:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:112:13 | LL | let _ = nan!() == number!(); | ^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = nan!() == number!(); -LL + let _ = f32::is_nan(number!()); +LL + let _ = ::std::primitive::f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:112:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:114:13 | LL | let _ = number!() != nan!(); | ^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = number!() != nan!(); -LL + let _ = !f32::is_nan(number!()); +LL + let _ = !::std::primitive::f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:117:13 + --> $DIR/invalid-nan-comparison-suggestion.rs:119:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - let _ = x == f64::NAN; -LL + let _ = f64::is_nan(x); +LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:122:8 + --> $DIR/invalid-nan-comparison-suggestion.rs:124:8 | LL | if x != &f32::NAN {} | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if x != &f32::NAN {} -LL + if !f32::is_nan(*x) {} +LL + if !::is_nan(*x) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:130:13 + | +LL | let _ = &x as &f64 == &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &x as &f64 == &f64::NAN; +LL + let _ = ::is_nan(*(&x as &f64)); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:132:13 + | +LL | let _ = { &{ 3.3 } } != &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = { &{ 3.3 } } != &f64::NAN; +LL + let _ = !::is_nan(*{ &{ 3.3 } }); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:133:12 + --> $DIR/invalid-nan-comparison-suggestion.rs:134:13 + | +LL | let _ = &&&3.3 == &&&f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &&&3.3 == &&&f64::NAN; +LL + let _ = ::is_nan(***&&&3.3); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:137:13 + | +LL | let _ = &&&f64::NAN != b; + | ^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &&&f64::NAN != b; +LL + let _ = !::is_nan(***b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:140:13 + | +LL | let _ = b != &f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &f64::NAN; +LL + let _ = !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:143:13 + | +LL | let _ = &(::NAN) == b; + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &(::NAN) == b; +LL + let _ = ::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:146:13 + | +LL | let _ = b != &{ f64::NAN }; + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &{ f64::NAN }; +LL + let _ = !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:149:13 + | +LL | let _ = &{ &{ f64::NAN } } == b; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = &{ &{ f64::NAN } } == b; +LL + let _ = ::is_nan(**b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:153:13 + | +LL | let _ = b != &f16::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &f16::NAN; +LL + let _ = !::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:156:13 + | +LL | let _ = b == &f128::NAN; + | ^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b == &f128::NAN; +LL + let _ = ::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:160:13 + | +LL | let _ = borrowed!() != &f64::NAN; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = borrowed!() != &f64::NAN; +LL + let _ = !::is_nan(*borrowed!()); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:170:13 + | +LL | let _ = b != &nan!(); + | ^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _ = b != &nan!(); +LL + let _ = !::std::primitive::f64::is_nan(*b); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:181:12 | LL | if b != &::core::primitive::f64::NAN {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if b != &::core::primitive::f64::NAN {} -LL + if !::core::primitive::f64::is_nan(*b) {} +LL + if !<::core::primitive::f64>::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:136:12 + --> $DIR/invalid-nan-comparison-suggestion.rs:184:12 | LL | if c != &Float::NAN {} | ^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - if c != &Float::NAN {} -LL + if !Float::is_nan(*c) {} +LL + if !::is_nan(*c) {} + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/invalid-nan-comparison-suggestion.rs:187:12 + | +LL | if d != &Float::r#NAN {} + | ^^^^^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - if d != &Float::r#NAN {} +LL + if !::is_nan(*d) {} | -warning: 31 warnings emitted +warning: 44 warnings emitted diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr index 4b31abf84ff54..3ee29a9fc4570 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparison.stderr @@ -5,10 +5,10 @@ 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 +help: use the `is_nan` method instead | LL - const TEST: bool = 5f32 == f32::NAN; -LL + const TEST: bool = f32::is_nan(5f32); +LL + const TEST: bool = ::is_nan(5f32); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -17,10 +17,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x == f16::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f16::NAN; -LL + f16::is_nan(x); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -29,10 +29,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x != f16::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f16::NAN; -LL + !f16::is_nan(x); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -65,10 +65,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | number!() == f16::NAN; | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f16::NAN; -LL + f16::is_nan(number!()); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -77,10 +77,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | f16::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f16::NAN != number!(); -LL + !f16::is_nan(number!()); +LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -89,10 +89,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x == f32::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f32::NAN; -LL + f32::is_nan(x); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -101,10 +101,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x != f32::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f32::NAN; -LL + !f32::is_nan(x); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -137,10 +137,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | number!() == f32::NAN; | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f32::NAN; -LL + f32::is_nan(number!()); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -149,10 +149,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | f32::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f32::NAN != number!(); -LL + !f32::is_nan(number!()); +LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -161,10 +161,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x == f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f64::NAN; -LL + f64::is_nan(x); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -173,10 +173,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x != f64::NAN; | ^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f64::NAN; -LL + !f64::is_nan(x); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -209,10 +209,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | number!() == f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f64::NAN; -LL + f64::is_nan(number!()); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -221,10 +221,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | f64::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f64::NAN != number!(); -LL + !f64::is_nan(number!()); +LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -233,10 +233,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x == f128::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x == f128::NAN; -LL + f128::is_nan(x); +LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -245,10 +245,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | x != f128::NAN; | ^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - x != f128::NAN; -LL + !f128::is_nan(x); +LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable @@ -281,10 +281,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | number!() == f128::NAN; | ^^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - number!() == f128::NAN; -LL + f128::is_nan(number!()); +LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself @@ -293,10 +293,10 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself LL | f128::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^^ | -help: use `f32::is_nan()` or `f64::is_nan()` instead +help: use the `is_nan` method instead | LL - f128::NAN != number!(); -LL + !f128::is_nan(number!()); +LL + !::is_nan(number!()); | warning: 33 warnings emitted From 142d509100ec3daf546ee77fe0c96b2ee9db10d7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 17 Oct 2026 12:43:04 -0700 Subject: [PATCH 06/14] Don't try to skip anything in `Skip::advance_by(0)` If we try to eagerly process our skip count, we might see the end of the inner iterator. `Iterator::advance_by` is supposed to return a non-zero `Err` count when exhausted, but there's no room for `Skip` to report anything in this case. So, it's better that we don't even try. --- library/core/src/iter/adapters/skip.rs | 8 ++++++ library/coretests/tests/iter/adapters/skip.rs | 25 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index f7a6beb2b8c63..600e897b13bbd 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -135,6 +135,14 @@ where #[inline] #[rustc_inherit_overflow_checks] fn advance_by(&mut self, mut n: usize) -> Result<(), NonZero> { + if self.n > 0 && n == 0 { + // If we try to process our skips now, we might witness the end of the inner iterator, + // but there's no valid `Err(k)` that we could return. This is especially a problem for + // unfused iterators that might end up called again by `Chain`, for example, so it's + // better that we do nothing at all. + return Ok(()); + } + let skip_inner = self.n; let skip_and_advance = skip_inner.saturating_add(n); diff --git a/library/coretests/tests/iter/adapters/skip.rs b/library/coretests/tests/iter/adapters/skip.rs index 8d5d06ad9fb3a..cfd00ac609715 100644 --- a/library/coretests/tests/iter/adapters/skip.rs +++ b/library/coretests/tests/iter/adapters/skip.rs @@ -86,6 +86,31 @@ fn test_skip_advance_by() { assert_eq!((0..0).skip(1).advance_back_by(0), Ok(())); } +#[test] +fn test_skip_unfused_advance_by() { + /// A legal non-fused iterator: `None` once, then `Some(1)`, `Some(2)`, ... + struct Gap(u32); + + impl Iterator for Gap { + type Item = u32; + fn next(&mut self) -> Option { + self.0 += 1; + if self.0 == 1 { None } else { Some(self.0 - 1) } + } + } + + assert_eq!(Gap(0).skip(1).next(), None); + + let mut iter = Gap(0).skip(1); + assert_eq!(iter.advance_by(0), Ok(())); + // `Ok` means we didn't see the (unfused) end yet... + assert_eq!(iter.next(), None); + + // Chain also depends on this behavior internally + assert_eq!(Gap(0).skip(1).chain(empty()).next(), None); + assert_eq!(Gap(0).skip(1).chain(empty()).nth(0), None); +} + #[test] fn test_iterator_skip_count() { let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; From abce4dc59670b5ad9a6b44c2c10820c342d319cb Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Oct 2026 12:45:35 +0200 Subject: [PATCH 07/14] Don't ignore unknown LLVM diagnostics Rust currently ignores LLVM diagnostic kinds that it does not know about. This means that we sometimes ignore error diagnostics, which can then result in silent miscompiles. This exposes `LLVMGetDiagInfoSeverity` returning `DiagnosticSeverity`, renamed from `DiagnosticLevel` to match LLVM terminology. Custom code to fetch the diagnostic severity for inline asm diagnostics can then be dropped. For unknown diagnostics, we emit a warning/error depending on severity. Notes and remarks continue to be ignored. One oddity I ran into along the way is that the linker diagnostic has severity error, but we only report a warning. I've kept this for now as we still error down the line and this ends up providing a bit more information (which file the duplicate symbol originates from). --- compiler/rustc_codegen_llvm/src/back/write.rs | 29 ++++++++----- .../rustc_codegen_llvm/src/llvm/diagnostic.rs | 20 ++++----- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 9 ++-- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 43 ++----------------- .../target-feature/too-many-reserved-regs.rs | 19 ++++++++ .../too-many-reserved-regs.stderr | 4 ++ 6 files changed, 60 insertions(+), 64 deletions(-) create mode 100644 tests/ui/target-feature/too-many-reserved-regs.rs create mode 100644 tests/ui/target-feature/too-many-reserved-regs.stderr diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 872c022373d45..7abf0789658b1 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -408,7 +408,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> { fn report_inline_asm( cgcx: &CodegenContext, msg: String, - level: llvm::DiagnosticLevel, + severity: llvm::DiagnosticSeverity, cookie: u64, source: Option<(String, Vec)>, ) -> InlineAsmError { @@ -422,10 +422,10 @@ fn report_inline_asm( let hi = BytePos::from_u32((cookie >> 32) as u32); (lo, hi) }; - let level = match level { - llvm::DiagnosticLevel::Error => Level::Error, - llvm::DiagnosticLevel::Warning => Level::Warning(None), - llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, + let level = match severity { + llvm::DiagnosticSeverity::Error => Level::Error, + llvm::DiagnosticSeverity::Warning => Level::Warning(None), + llvm::DiagnosticSeverity::Note | llvm::DiagnosticSeverity::Remark => Level::Note, }; let msg = msg.trim_prefix("error: ").to_string(); InlineAsmError { lo, hi, msg, level, source } @@ -456,7 +456,7 @@ fn diagnostic_handler_callback_inner( shared_emitter.inline_asm_error(report_inline_asm( cgcx, inline.message, - inline.level, + inline.severity, inline.cookie, inline.source, )); @@ -479,21 +479,30 @@ fn diagnostic_handler_callback_inner( message: &opt.message, }); } - llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => { + llvm::diagnostic::Linker(diagnostic_ref) => { let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); dcx.emit_warn(FromLlvmDiag { message }); } - llvm::diagnostic::Unsupported(diagnostic_ref) => { + llvm::diagnostic::PGO(diagnostic_ref) + | llvm::diagnostic::Unsupported(diagnostic_ref) + | llvm::diagnostic::UnknownDiagnostic(diagnostic_ref) => { let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); - dcx.emit_err(FromLlvmDiag { message }); + match diagnostic_ref.severity() { + llvm::DiagnosticSeverity::Error => { + dcx.emit_err(FromLlvmDiag { message }); + } + llvm::DiagnosticSeverity::Warning => { + dcx.emit_warn(FromLlvmDiag { message }); + } + _ => {} + }; } - llvm::diagnostic::UnknownDiagnostic(..) => {} } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 59b2cd329ae76..e65f1e9d9f890 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -75,7 +75,6 @@ impl<'ll> OptimizationDiagnostic<'ll> { } pub(crate) struct SrcMgrDiagnostic { - pub level: super::DiagnosticLevel, pub message: String, pub source: Option<(String, Vec)>, } @@ -86,7 +85,6 @@ impl SrcMgrDiagnostic { // diagnostics. let mut have_source = false; let mut buffer = String::new(); - let mut level = super::DiagnosticLevel::Error; let mut loc = 0; let mut ranges = [0; 8]; let mut num_ranges = ranges.len() / 2; @@ -96,7 +94,6 @@ impl SrcMgrDiagnostic { diag, message, buffer, - &mut level, &mut loc, ranges.as_mut_ptr(), &mut num_ranges, @@ -108,7 +105,6 @@ impl SrcMgrDiagnostic { SrcMgrDiagnostic { message, - level, source: have_source.then(|| { let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)]; for i in 0..num_ranges { @@ -122,7 +118,7 @@ impl SrcMgrDiagnostic { #[derive(Clone)] pub(crate) struct InlineAsmDiagnostic { - pub level: super::DiagnosticLevel, + pub severity: super::DiagnosticSeverity, pub cookie: u64, pub message: String, pub source: Option<(String, Vec)>, @@ -132,14 +128,13 @@ impl InlineAsmDiagnostic { unsafe fn unpackInlineAsm(di: &DiagnosticInfo) -> Self { let mut cookie = 0; let mut message = None; - let mut level = super::DiagnosticLevel::Error; unsafe { - super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); + super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut cookie, &mut message); } InlineAsmDiagnostic { - level, + severity: di.severity(), cookie, message: super::twine_to_string(message.unwrap()), source: None, @@ -151,7 +146,7 @@ impl InlineAsmDiagnostic { let smdiag = unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { - level: smdiag.level, + severity: di.severity(), cookie, message: smdiag.message, source: smdiag.source, @@ -167,7 +162,6 @@ pub(crate) enum Diagnostic<'ll> { Unsupported(&'ll DiagnosticInfo), /// LLVM has other types that we do not wrap here. - #[expect(dead_code)] UnknownDiagnostic(&'ll DiagnosticInfo), } @@ -217,3 +211,9 @@ impl<'ll> Diagnostic<'ll> { } } } + +impl DiagnosticInfo { + pub(crate) fn severity(&self) -> super::DiagnosticSeverity { + unsafe { super::LLVMGetDiagInfoSeverity(self) } + } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a8ededf305a29..cc9be9a0d5093 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -551,15 +551,15 @@ pub(crate) enum DiagnosticKind { SrcMgr, } -/// LLVMRustDiagnosticLevel +/// LLVMDiagnosticSeverity #[derive(Copy, Clone)] #[repr(C)] #[allow(dead_code)] // Variants constructed by C++. -pub(crate) enum DiagnosticLevel { +pub(crate) enum DiagnosticSeverity { Error, Warning, - Note, Remark, + Note, } unsafe extern "C" { @@ -2502,13 +2502,13 @@ unsafe extern "C" { pub(crate) fn LLVMRustUnpackInlineAsmDiagnostic<'a>( DI: &'a DiagnosticInfo, - level_out: &mut DiagnosticLevel, cookie_out: &mut u64, message_out: &mut Option<&'a Twine>, ); pub(crate) fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString); pub(crate) fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind; + pub(crate) fn LLVMGetDiagInfoSeverity(DI: &DiagnosticInfo) -> DiagnosticSeverity; pub(crate) fn LLVMRustGetSMDiagnostic<'a>( DI: &'a DiagnosticInfo, @@ -2519,7 +2519,6 @@ unsafe extern "C" { d: &SMDiagnostic, message_out: &RustString, buffer_out: &RustString, - level_out: &mut DiagnosticLevel, loc_out: &mut c_uint, ranges_out: *mut c_uint, num_ranges: &mut usize, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f379799ecde9e..1edc547023b9c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1217,32 +1217,15 @@ enum class LLVMRustDiagnosticLevel { Remark, }; -extern "C" void LLVMRustUnpackInlineAsmDiagnostic( - LLVMDiagnosticInfoRef DI, LLVMRustDiagnosticLevel *LevelOut, - uint64_t *CookieOut, const Twine **MessageOut) { +extern "C" void LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, + uint64_t *CookieOut, + const Twine **MessageOut) { // Undefined to call this not on an inline assembly diagnostic! llvm::DiagnosticInfoInlineAsm *IA = static_cast(unwrap(DI)); *CookieOut = IA->getLocCookie(); *MessageOut = &IA->getMsgStr(); - - switch (IA->getSeverity()) { - case DS_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case DS_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case DS_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case DS_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); - } } extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef DI, @@ -1324,30 +1307,12 @@ extern "C" const SMDiagnostic *LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, extern "C" bool LLVMRustUnpackSMDiagnostic(const SMDiagnostic *DRef, RustStringRef MessageOut, - RustStringRef BufferOut, - LLVMRustDiagnosticLevel *LevelOut, unsigned *LocOut, + RustStringRef BufferOut, unsigned *LocOut, unsigned *RangesOut, size_t *NumRanges) { const SMDiagnostic &D = *DRef; auto MessageOS = RawRustStringOstream(MessageOut); MessageOS << D.getMessage(); - switch (D.getKind()) { - case SourceMgr::DK_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case SourceMgr::DK_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case SourceMgr::DK_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case SourceMgr::DK_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); - } - if (D.getLoc() == SMLoc()) return false; diff --git a/tests/ui/target-feature/too-many-reserved-regs.rs b/tests/ui/target-feature/too-many-reserved-regs.rs new file mode 100644 index 0000000000000..f53d6eb2b2251 --- /dev/null +++ b/tests/ui/target-feature/too-many-reserved-regs.rs @@ -0,0 +1,19 @@ +//@ build-fail +//@ add-minicore +//@ ignore-backends: gcc +//@ needs-llvm-components: riscv +//@ compile-flags: --target=riscv64gc-unknown-linux-gnu -Copt-level=3 -Zllvm-target-feature=+reserve-x1,+reserve-x3,+reserve-x4,+reserve-x5,+reserve-x6,+reserve-x7,+reserve-x8,+reserve-x9,+reserve-x11,+reserve-x12,+reserve-x13,+reserve-x14,+reserve-x15,+reserve-x16,+reserve-x17,+reserve-x18,+reserve-x19,+reserve-x20,+reserve-x21,+reserve-x22,+reserve-x23,+reserve-x24,+reserve-x25,+reserve-x26,+reserve-x27,+reserve-x28,+reserve-x29,+reserve-x30,+reserve-x31 + +#![feature(no_core)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[unsafe(no_mangle)] +pub unsafe fn store_val(dst: *mut u32) { + minicore::ptr::write_volatile(dst, 42); +} + +//~? ERROR ran out of registers during register allocation in function 'store_val' diff --git a/tests/ui/target-feature/too-many-reserved-regs.stderr b/tests/ui/target-feature/too-many-reserved-regs.stderr new file mode 100644 index 0000000000000..3a3e3f33abea8 --- /dev/null +++ b/tests/ui/target-feature/too-many-reserved-regs.stderr @@ -0,0 +1,4 @@ +error: :0:0: ran out of registers during register allocation in function 'store_val' + +error: aborting due to 1 previous error + From 2c2a5e9c24e5078ec5d338e8087bdfdf963c9b59 Mon Sep 17 00:00:00 2001 From: Yu Date: Mon, 19 Oct 2026 22:30:17 +0800 Subject: [PATCH 08/14] test: re-organize ui test case --- .../basic.rs} | 0 .../basic.stderr} | 66 +++++++------- .../custom-partial-eq.rs} | 0 .../custom-partial-eq.stderr} | 6 +- .../no-std.fixed} | 0 .../no-std.rs} | 0 .../no-std.stderr} | 2 +- .../no-suggestion.rs} | 0 .../no-suggestion.stderr} | 10 +-- .../suggestion.fixed} | 0 .../suggestion.rs} | 0 .../suggestion.stderr} | 88 +++++++++---------- 12 files changed, 86 insertions(+), 86 deletions(-) rename tests/ui/lint/{invalid-nan-comparison.rs => invalid-nan-comparisons/basic.rs} (100%) rename tests/ui/lint/{invalid-nan-comparison.stderr => invalid-nan-comparisons/basic.stderr} (81%) rename tests/ui/lint/{invalid-nan-comparison-custom-partial-eq.rs => invalid-nan-comparisons/custom-partial-eq.rs} (100%) rename tests/ui/lint/{invalid-nan-comparison-custom-partial-eq.stderr => invalid-nan-comparisons/custom-partial-eq.stderr} (79%) rename tests/ui/lint/{invalid-nan-comparison-no-std.fixed => invalid-nan-comparisons/no-std.fixed} (100%) rename tests/ui/lint/{invalid-nan-comparison-no-std.rs => invalid-nan-comparisons/no-std.rs} (100%) rename tests/ui/lint/{invalid-nan-comparison-no-std.stderr => invalid-nan-comparisons/no-std.stderr} (88%) rename tests/ui/lint/{invalid-nan-comparison-no-suggestion.rs => invalid-nan-comparisons/no-suggestion.rs} (100%) rename tests/ui/lint/{invalid-nan-comparison-no-suggestion.stderr => invalid-nan-comparisons/no-suggestion.stderr} (81%) rename tests/ui/lint/{invalid-nan-comparison-suggestion.fixed => invalid-nan-comparisons/suggestion.fixed} (100%) rename tests/ui/lint/{invalid-nan-comparison-suggestion.rs => invalid-nan-comparisons/suggestion.rs} (100%) rename tests/ui/lint/{invalid-nan-comparison-suggestion.stderr => invalid-nan-comparisons/suggestion.stderr} (83%) diff --git a/tests/ui/lint/invalid-nan-comparison.rs b/tests/ui/lint/invalid-nan-comparisons/basic.rs similarity index 100% rename from tests/ui/lint/invalid-nan-comparison.rs rename to tests/ui/lint/invalid-nan-comparisons/basic.rs diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparisons/basic.stderr similarity index 81% rename from tests/ui/lint/invalid-nan-comparison.stderr rename to tests/ui/lint/invalid-nan-comparisons/basic.stderr index 3ee29a9fc4570..77cd6fc111e75 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/basic.stderr @@ -1,5 +1,5 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:12:20 + --> $DIR/basic.rs:12:20 | LL | const TEST: bool = 5f32 == f32::NAN; | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + const TEST: bool = ::is_nan(5f32); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:18:5 + --> $DIR/basic.rs:18:5 | LL | x == f16::NAN; | ^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:20:5 + --> $DIR/basic.rs:20:5 | LL | x != f16::NAN; | ^^^^^^^^^^^^^ @@ -36,31 +36,31 @@ LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:22:5 + --> $DIR/basic.rs:22:5 | LL | x < f16::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:24:5 + --> $DIR/basic.rs:24:5 | LL | x > f16::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:26:5 + --> $DIR/basic.rs:26:5 | LL | x <= f16::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:28:5 + --> $DIR/basic.rs:28:5 | LL | x >= f16::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:30:5 + --> $DIR/basic.rs:30:5 | LL | number!() == f16::NAN; | ^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:32:5 + --> $DIR/basic.rs:32:5 | LL | f16::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:39:5 + --> $DIR/basic.rs:39:5 | LL | x == f32::NAN; | ^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:41:5 + --> $DIR/basic.rs:41:5 | LL | x != f32::NAN; | ^^^^^^^^^^^^^ @@ -108,31 +108,31 @@ LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:43:5 + --> $DIR/basic.rs:43:5 | LL | x < f32::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:45:5 + --> $DIR/basic.rs:45:5 | LL | x > f32::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:47:5 + --> $DIR/basic.rs:47:5 | LL | x <= f32::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:49:5 + --> $DIR/basic.rs:49:5 | LL | x >= f32::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:51:5 + --> $DIR/basic.rs:51:5 | LL | number!() == f32::NAN; | ^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:53:5 + --> $DIR/basic.rs:53:5 | LL | f32::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:60:5 + --> $DIR/basic.rs:60:5 | LL | x == f64::NAN; | ^^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:62:5 + --> $DIR/basic.rs:62:5 | LL | x != f64::NAN; | ^^^^^^^^^^^^^ @@ -180,31 +180,31 @@ LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:64:5 + --> $DIR/basic.rs:64:5 | LL | x < f64::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:66:5 + --> $DIR/basic.rs:66:5 | LL | x > f64::NAN; | ^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:68:5 + --> $DIR/basic.rs:68:5 | LL | x <= f64::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:70:5 + --> $DIR/basic.rs:70:5 | LL | x >= f64::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:72:5 + --> $DIR/basic.rs:72:5 | LL | number!() == f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^ @@ -216,7 +216,7 @@ LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:74:5 + --> $DIR/basic.rs:74:5 | LL | f64::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -228,7 +228,7 @@ LL + !::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:81:5 + --> $DIR/basic.rs:81:5 | LL | x == f128::NAN; | ^^^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL + ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:83:5 + --> $DIR/basic.rs:83:5 | LL | x != f128::NAN; | ^^^^^^^^^^^^^^ @@ -252,31 +252,31 @@ LL + !::is_nan(x); | warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:85:5 + --> $DIR/basic.rs:85:5 | LL | x < f128::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:87:5 + --> $DIR/basic.rs:87:5 | LL | x > f128::NAN; | ^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:89:5 + --> $DIR/basic.rs:89:5 | LL | x <= f128::NAN; | ^^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN is not orderable - --> $DIR/invalid-nan-comparison.rs:91:5 + --> $DIR/basic.rs:91:5 | LL | x >= f128::NAN; | ^^^^^^^^^^^^^^ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:93:5 + --> $DIR/basic.rs:93:5 | LL | number!() == f128::NAN; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ LL + ::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison.rs:95:5 + --> $DIR/basic.rs:95:5 | LL | f128::NAN != number!(); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs b/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.rs similarity index 100% rename from tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs rename to tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.rs diff --git a/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr b/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr similarity index 79% rename from tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr rename to tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr index daf91b092a3bb..f0c914dccdce6 100644 --- a/tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr @@ -1,5 +1,5 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-custom-partial-eq.rs:19:13 + --> $DIR/custom-partial-eq.rs:19:13 | LL | let _ = value == f64::NAN; | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = value == f64::NAN; = note: `#[warn(invalid_nan_comparisons)]` on by default warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-custom-partial-eq.rs:21:13 + --> $DIR/custom-partial-eq.rs:21:13 | LL | let _ = f64::NAN != value; | ^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = f64::NAN != value; = help: use the `is_nan` method instead warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-custom-partial-eq.rs:23:13 + --> $DIR/custom-partial-eq.rs:23:13 | LL | let _ = &value != &f64::NAN; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/invalid-nan-comparison-no-std.fixed b/tests/ui/lint/invalid-nan-comparisons/no-std.fixed similarity index 100% rename from tests/ui/lint/invalid-nan-comparison-no-std.fixed rename to tests/ui/lint/invalid-nan-comparisons/no-std.fixed diff --git a/tests/ui/lint/invalid-nan-comparison-no-std.rs b/tests/ui/lint/invalid-nan-comparisons/no-std.rs similarity index 100% rename from tests/ui/lint/invalid-nan-comparison-no-std.rs rename to tests/ui/lint/invalid-nan-comparisons/no-std.rs diff --git a/tests/ui/lint/invalid-nan-comparison-no-std.stderr b/tests/ui/lint/invalid-nan-comparisons/no-std.stderr similarity index 88% rename from tests/ui/lint/invalid-nan-comparison-no-std.stderr rename to tests/ui/lint/invalid-nan-comparisons/no-std.stderr index 143736b352ad9..b10909e157020 100644 --- a/tests/ui/lint/invalid-nan-comparison-no-std.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/no-std.stderr @@ -1,5 +1,5 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-no-std.rs:16:13 + --> $DIR/no-std.rs:16:13 | LL | let _ = b != &nan!(); | ^^^^^^^^^^^^ diff --git a/tests/ui/lint/invalid-nan-comparison-no-suggestion.rs b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.rs similarity index 100% rename from tests/ui/lint/invalid-nan-comparison-no-suggestion.rs rename to tests/ui/lint/invalid-nan-comparisons/no-suggestion.rs diff --git a/tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.stderr similarity index 81% rename from tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr rename to tests/ui/lint/invalid-nan-comparisons/no-suggestion.stderr index 659deb868b027..278f4d225aec4 100644 --- a/tests/ui/lint/invalid-nan-comparison-no-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/no-suggestion.stderr @@ -1,5 +1,5 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-no-suggestion.rs:7:13 + --> $DIR/no-suggestion.rs:7:13 | LL | let _ = 3.3 == { | _____________^ @@ -12,7 +12,7 @@ LL | | }; = note: `#[warn(invalid_nan_comparisons)]` on by default warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-no-suggestion.rs:15:13 + --> $DIR/no-suggestion.rs:15:13 | LL | let _ = 3.3 == scoped_nan!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | let _ = 3.3 == scoped_nan!(); = help: use the `is_nan` method instead warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-no-suggestion.rs:19:13 + --> $DIR/no-suggestion.rs:19:13 | LL | let _ = 3.3 == nan16!(); | ^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _ = 3.3 == nan16!(); = help: use the `is_nan` method instead warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-no-suggestion.rs:22:13 + --> $DIR/no-suggestion.rs:22:13 | LL | let _ = 3.3 != nan128!(); | ^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _ = 3.3 != nan128!(); = help: use the `is_nan` method instead warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-no-suggestion.rs:25:36 + --> $DIR/no-suggestion.rs:25:36 | LL | macro_rules! compare { () => { 3.3 != f64::NAN }; } | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.fixed b/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed similarity index 100% rename from tests/ui/lint/invalid-nan-comparison-suggestion.fixed rename to tests/ui/lint/invalid-nan-comparisons/suggestion.fixed diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.rs b/tests/ui/lint/invalid-nan-comparisons/suggestion.rs similarity index 100% rename from tests/ui/lint/invalid-nan-comparison-suggestion.rs rename to tests/ui/lint/invalid-nan-comparisons/suggestion.rs diff --git a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr b/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr similarity index 83% rename from tests/ui/lint/invalid-nan-comparison-suggestion.stderr rename to tests/ui/lint/invalid-nan-comparisons/suggestion.stderr index 9c920496c3f54..467e97be03f57 100644 --- a/tests/ui/lint/invalid-nan-comparison-suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr @@ -1,5 +1,5 @@ warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:10:13 + --> $DIR/suggestion.rs:10:13 | LL | let _ = x == f16::NAN; | ^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:12:13 + --> $DIR/suggestion.rs:12:13 | LL | let _ = x != f16::NAN; | ^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:16:13 + --> $DIR/suggestion.rs:16:13 | LL | let _ = x == f32::NAN; | ^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:18:13 + --> $DIR/suggestion.rs:18:13 | LL | let _ = x != f32::NAN; | ^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:22:13 + --> $DIR/suggestion.rs:22:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:24:13 + --> $DIR/suggestion.rs:24:13 | LL | let _ = x != f64::NAN; | ^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:28:13 + --> $DIR/suggestion.rs:28:13 | LL | let _ = x == f128::NAN; | ^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:30:13 + --> $DIR/suggestion.rs:30:13 | LL | let _ = x != f128::NAN; | ^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + let _ = !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:34:8 + --> $DIR/suggestion.rs:34:8 | LL | if b != &f32::NAN {} | ^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + if !::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:38:8 + --> $DIR/suggestion.rs:38:8 | LL | if b != { &f32::NAN } {} | ^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + if !::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:42:9 + --> $DIR/suggestion.rs:42:9 | LL | / b != { LL | | @@ -138,7 +138,7 @@ LL + !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:50:8 + --> $DIR/suggestion.rs:50:8 | LL | if b != &f64::NAN {} | ^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL + if !::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:54:8 + --> $DIR/suggestion.rs:54:8 | LL | if m != &f64::NAN { | ^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL + if !::is_nan(*m) { | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:61:8 + --> $DIR/suggestion.rs:61:8 | LL | if unary != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ LL + if !::is_nan(*unary) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:65:8 + --> $DIR/suggestion.rs:65:8 | LL | if block != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -186,7 +186,7 @@ LL + if !::is_nan(*block) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:69:8 + --> $DIR/suggestion.rs:69:8 | LL | if tuple != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL + if !::is_nan(*tuple) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:73:8 + --> $DIR/suggestion.rs:73:8 | LL | if arithmetic != &f64::NAN {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +210,7 @@ LL + if !::is_nan(*arithmetic) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:77:8 + --> $DIR/suggestion.rs:77:8 | LL | if &x != &f64::NAN {} | ^^^^^^^^^^^^^^^ @@ -222,7 +222,7 @@ LL + if !::is_nan(*&x) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:80:13 + --> $DIR/suggestion.rs:80:13 | LL | let _ = *p == f64::NAN; | ^^^^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL + let _ = ::is_nan(*p); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:82:13 + --> $DIR/suggestion.rs:82:13 | LL | let _ = -x == f64::NAN; | ^^^^^^^^^^^^^^ @@ -246,7 +246,7 @@ LL + let _ = ::is_nan(-x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:89:13 + --> $DIR/suggestion.rs:89:13 | LL | let _ = 3.3 == f64::NAN; | ^^^^^^^^^^^^^^^ @@ -258,7 +258,7 @@ LL + let _ = ::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:92:13 + --> $DIR/suggestion.rs:92:13 | LL | let _ = &3.3 != &f64::NAN; | ^^^^^^^^^^^^^^^^^ @@ -270,7 +270,7 @@ LL + let _ = !::is_nan(*&3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:97:13 + --> $DIR/suggestion.rs:97:13 | LL | let _ = copied != f64::NAN; | ^^^^^^^^^^^^^^^^^^ @@ -282,7 +282,7 @@ LL + let _ = !::is_nan(copied); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:101:13 + --> $DIR/suggestion.rs:101:13 | LL | let _ = ascribed != f64::NAN; | ^^^^^^^^^^^^^^^^^^^^ @@ -294,7 +294,7 @@ LL + let _ = !::is_nan(ascribed); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:106:22 + --> $DIR/suggestion.rs:106:22 | LL | let _ = |x: f64| x != f64::NAN; | ^^^^^^^^^^^^^ @@ -306,7 +306,7 @@ LL + let _ = |x: f64| !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:112:13 + --> $DIR/suggestion.rs:112:13 | LL | let _ = nan!() == number!(); | ^^^^^^^^^^^^^^^^^^^ @@ -318,7 +318,7 @@ LL + let _ = ::std::primitive::f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:114:13 + --> $DIR/suggestion.rs:114:13 | LL | let _ = number!() != nan!(); | ^^^^^^^^^^^^^^^^^^^ @@ -330,7 +330,7 @@ LL + let _ = !::std::primitive::f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:119:13 + --> $DIR/suggestion.rs:119:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ @@ -342,7 +342,7 @@ LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:124:8 + --> $DIR/suggestion.rs:124:8 | LL | if x != &f32::NAN {} | ^^^^^^^^^^^^^^ @@ -354,7 +354,7 @@ LL + if !::is_nan(*x) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:130:13 + --> $DIR/suggestion.rs:130:13 | LL | let _ = &x as &f64 == &f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL + let _ = ::is_nan(*(&x as &f64)); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:132:13 + --> $DIR/suggestion.rs:132:13 | LL | let _ = { &{ 3.3 } } != &f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -378,7 +378,7 @@ LL + let _ = !::is_nan(*{ &{ 3.3 } }); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:134:13 + --> $DIR/suggestion.rs:134:13 | LL | let _ = &&&3.3 == &&&f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^ @@ -390,7 +390,7 @@ LL + let _ = ::is_nan(***&&&3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:137:13 + --> $DIR/suggestion.rs:137:13 | LL | let _ = &&&f64::NAN != b; | ^^^^^^^^^^^^^^^^ @@ -402,7 +402,7 @@ LL + let _ = !::is_nan(***b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:140:13 + --> $DIR/suggestion.rs:140:13 | LL | let _ = b != &f64::NAN; | ^^^^^^^^^^^^^^ @@ -414,7 +414,7 @@ LL + let _ = !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:143:13 + --> $DIR/suggestion.rs:143:13 | LL | let _ = &(::NAN) == b; | ^^^^^^^^^^^^^^^^^^ @@ -426,7 +426,7 @@ LL + let _ = ::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:146:13 + --> $DIR/suggestion.rs:146:13 | LL | let _ = b != &{ f64::NAN }; | ^^^^^^^^^^^^^^^^^^ @@ -438,7 +438,7 @@ LL + let _ = !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:149:13 + --> $DIR/suggestion.rs:149:13 | LL | let _ = &{ &{ f64::NAN } } == b; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -450,7 +450,7 @@ LL + let _ = ::is_nan(**b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:153:13 + --> $DIR/suggestion.rs:153:13 | LL | let _ = b != &f16::NAN; | ^^^^^^^^^^^^^^ @@ -462,7 +462,7 @@ LL + let _ = !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:156:13 + --> $DIR/suggestion.rs:156:13 | LL | let _ = b == &f128::NAN; | ^^^^^^^^^^^^^^^ @@ -474,7 +474,7 @@ LL + let _ = ::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:160:13 + --> $DIR/suggestion.rs:160:13 | LL | let _ = borrowed!() != &f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -486,7 +486,7 @@ LL + let _ = !::is_nan(*borrowed!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:170:13 + --> $DIR/suggestion.rs:170:13 | LL | let _ = b != &nan!(); | ^^^^^^^^^^^^ @@ -498,7 +498,7 @@ LL + let _ = !::std::primitive::f64::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:181:12 + --> $DIR/suggestion.rs:181:12 | LL | if b != &::core::primitive::f64::NAN {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +510,7 @@ LL + if !<::core::primitive::f64>::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:184:12 + --> $DIR/suggestion.rs:184:12 | LL | if c != &Float::NAN {} | ^^^^^^^^^^^^^^^^ @@ -522,7 +522,7 @@ LL + if !::is_nan(*c) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/invalid-nan-comparison-suggestion.rs:187:12 + --> $DIR/suggestion.rs:187:12 | LL | if d != &Float::r#NAN {} | ^^^^^^^^^^^^^^^^^^ From d201932dcbf01ba8217d4fd99860dab878a7887c Mon Sep 17 00:00:00 2001 From: Yu Date: Mon, 19 Oct 2026 22:38:19 +0800 Subject: [PATCH 09/14] test: cover shadowing in qualified NaN suggestions --- .../invalid-nan-comparisons/suggestion.fixed | 28 +++++++ .../invalid-nan-comparisons/suggestion.rs | 28 +++++++ .../invalid-nan-comparisons/suggestion.stderr | 74 ++++++++++++------- 3 files changed, 105 insertions(+), 25 deletions(-) diff --git a/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed b/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed index d3043e3f72516..be5f477e67992 100644 --- a/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.fixed @@ -82,6 +82,7 @@ fn main() { shadowed::check(); nested_operands(); macro_paths(); + method_resolution::check(); let _ = ::is_nan(3.3); //~^ WARN incorrect NaN comparison @@ -185,3 +186,30 @@ mod shadowed { //~^ WARN incorrect NaN comparison } } + +mod method_resolution { + mod f64 { + pub fn is_nan(_: ::core::primitive::f64) {} + } + + trait IsNan { + fn is_nan(self); + } + + impl IsNan for &f64 { + fn is_nan(self) {} + } + + pub fn check() { + let _: () = f64::is_nan(5.0); + let _: () = (&5f64).is_nan(); + + let x = 5f64; + let _: bool = ::is_nan(x); + //~^ WARN incorrect NaN comparison + + let x = &5f64; + let _: bool = ::is_nan(*x); + //~^ WARN incorrect NaN comparison + } +} diff --git a/tests/ui/lint/invalid-nan-comparisons/suggestion.rs b/tests/ui/lint/invalid-nan-comparisons/suggestion.rs index d5376db904453..96b7618e921e9 100644 --- a/tests/ui/lint/invalid-nan-comparisons/suggestion.rs +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.rs @@ -85,6 +85,7 @@ fn main() { shadowed::check(); nested_operands(); macro_paths(); + method_resolution::check(); let _ = 3.3 == f64::NAN; //~^ WARN incorrect NaN comparison @@ -188,3 +189,30 @@ mod shadowed { //~^ WARN incorrect NaN comparison } } + +mod method_resolution { + mod f64 { + pub fn is_nan(_: ::core::primitive::f64) {} + } + + trait IsNan { + fn is_nan(self); + } + + impl IsNan for &f64 { + fn is_nan(self) {} + } + + pub fn check() { + let _: () = f64::is_nan(5.0); + let _: () = (&5f64).is_nan(); + + let x = 5f64; + let _: bool = x == f64::NAN; + //~^ WARN incorrect NaN comparison + + let x = &5f64; + let _: bool = x == &f64::NAN; + //~^ WARN incorrect NaN comparison + } +} diff --git a/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr b/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr index 467e97be03f57..50d5684dbb2c1 100644 --- a/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr +++ b/tests/ui/lint/invalid-nan-comparisons/suggestion.stderr @@ -246,7 +246,7 @@ LL + let _ = ::is_nan(-x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:89:13 + --> $DIR/suggestion.rs:90:13 | LL | let _ = 3.3 == f64::NAN; | ^^^^^^^^^^^^^^^ @@ -258,7 +258,7 @@ LL + let _ = ::is_nan(3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:92:13 + --> $DIR/suggestion.rs:93:13 | LL | let _ = &3.3 != &f64::NAN; | ^^^^^^^^^^^^^^^^^ @@ -270,7 +270,7 @@ LL + let _ = !::is_nan(*&3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:97:13 + --> $DIR/suggestion.rs:98:13 | LL | let _ = copied != f64::NAN; | ^^^^^^^^^^^^^^^^^^ @@ -282,7 +282,7 @@ LL + let _ = !::is_nan(copied); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:101:13 + --> $DIR/suggestion.rs:102:13 | LL | let _ = ascribed != f64::NAN; | ^^^^^^^^^^^^^^^^^^^^ @@ -294,7 +294,7 @@ LL + let _ = !::is_nan(ascribed); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:106:22 + --> $DIR/suggestion.rs:107:22 | LL | let _ = |x: f64| x != f64::NAN; | ^^^^^^^^^^^^^ @@ -306,7 +306,7 @@ LL + let _ = |x: f64| !::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:112:13 + --> $DIR/suggestion.rs:113:13 | LL | let _ = nan!() == number!(); | ^^^^^^^^^^^^^^^^^^^ @@ -318,7 +318,7 @@ LL + let _ = ::std::primitive::f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:114:13 + --> $DIR/suggestion.rs:115:13 | LL | let _ = number!() != nan!(); | ^^^^^^^^^^^^^^^^^^^ @@ -330,7 +330,7 @@ LL + let _ = !::std::primitive::f32::is_nan(number!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:119:13 + --> $DIR/suggestion.rs:120:13 | LL | let _ = x == f64::NAN; | ^^^^^^^^^^^^^ @@ -342,7 +342,7 @@ LL + let _ = ::is_nan(x); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:124:8 + --> $DIR/suggestion.rs:125:8 | LL | if x != &f32::NAN {} | ^^^^^^^^^^^^^^ @@ -354,7 +354,7 @@ LL + if !::is_nan(*x) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:130:13 + --> $DIR/suggestion.rs:131:13 | LL | let _ = &x as &f64 == &f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL + let _ = ::is_nan(*(&x as &f64)); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:132:13 + --> $DIR/suggestion.rs:133:13 | LL | let _ = { &{ 3.3 } } != &f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -378,7 +378,7 @@ LL + let _ = !::is_nan(*{ &{ 3.3 } }); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:134:13 + --> $DIR/suggestion.rs:135:13 | LL | let _ = &&&3.3 == &&&f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^ @@ -390,7 +390,7 @@ LL + let _ = ::is_nan(***&&&3.3); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:137:13 + --> $DIR/suggestion.rs:138:13 | LL | let _ = &&&f64::NAN != b; | ^^^^^^^^^^^^^^^^ @@ -402,7 +402,7 @@ LL + let _ = !::is_nan(***b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:140:13 + --> $DIR/suggestion.rs:141:13 | LL | let _ = b != &f64::NAN; | ^^^^^^^^^^^^^^ @@ -414,7 +414,7 @@ LL + let _ = !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:143:13 + --> $DIR/suggestion.rs:144:13 | LL | let _ = &(::NAN) == b; | ^^^^^^^^^^^^^^^^^^ @@ -426,7 +426,7 @@ LL + let _ = ::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:146:13 + --> $DIR/suggestion.rs:147:13 | LL | let _ = b != &{ f64::NAN }; | ^^^^^^^^^^^^^^^^^^ @@ -438,7 +438,7 @@ LL + let _ = !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:149:13 + --> $DIR/suggestion.rs:150:13 | LL | let _ = &{ &{ f64::NAN } } == b; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -450,7 +450,7 @@ LL + let _ = ::is_nan(**b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:153:13 + --> $DIR/suggestion.rs:154:13 | LL | let _ = b != &f16::NAN; | ^^^^^^^^^^^^^^ @@ -462,7 +462,7 @@ LL + let _ = !::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:156:13 + --> $DIR/suggestion.rs:157:13 | LL | let _ = b == &f128::NAN; | ^^^^^^^^^^^^^^^ @@ -474,7 +474,7 @@ LL + let _ = ::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:160:13 + --> $DIR/suggestion.rs:161:13 | LL | let _ = borrowed!() != &f64::NAN; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -486,7 +486,7 @@ LL + let _ = !::is_nan(*borrowed!()); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:170:13 + --> $DIR/suggestion.rs:171:13 | LL | let _ = b != &nan!(); | ^^^^^^^^^^^^ @@ -498,7 +498,7 @@ LL + let _ = !::std::primitive::f64::is_nan(*b); | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:181:12 + --> $DIR/suggestion.rs:182:12 | LL | if b != &::core::primitive::f64::NAN {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +510,7 @@ LL + if !<::core::primitive::f64>::is_nan(*b) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:184:12 + --> $DIR/suggestion.rs:185:12 | LL | if c != &Float::NAN {} | ^^^^^^^^^^^^^^^^ @@ -522,7 +522,7 @@ LL + if !::is_nan(*c) {} | warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/suggestion.rs:187:12 + --> $DIR/suggestion.rs:188:12 | LL | if d != &Float::r#NAN {} | ^^^^^^^^^^^^^^^^^^ @@ -533,5 +533,29 @@ LL - if d != &Float::r#NAN {} LL + if !::is_nan(*d) {} | -warning: 44 warnings emitted +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:211:23 + | +LL | let _: bool = x == f64::NAN; + | ^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _: bool = x == f64::NAN; +LL + let _: bool = ::is_nan(x); + | + +warning: incorrect NaN comparison, NaN cannot be directly compared to itself + --> $DIR/suggestion.rs:215:23 + | +LL | let _: bool = x == &f64::NAN; + | ^^^^^^^^^^^^^^ + | +help: use the `is_nan` method instead + | +LL - let _: bool = x == &f64::NAN; +LL + let _: bool = ::is_nan(*x); + | + +warning: 46 warnings emitted From 3b9350aa2ca884c952656a084dd686b62483170c Mon Sep 17 00:00:00 2001 From: Yu Date: Mon, 19 Oct 2026 23:05:31 +0800 Subject: [PATCH 10/14] lint: skip NaN diagnostics for custom comparisons --- compiler/rustc_lint/src/types.rs | 39 +++++----- .../custom-comparisons.rs | 73 +++++++++++++++++++ .../custom-partial-eq.rs | 25 ------- .../custom-partial-eq.stderr | 27 ------- 4 files changed, 92 insertions(+), 72 deletions(-) create mode 100644 tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs delete mode 100644 tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.rs delete mode 100644 tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index c38e77c5fe6c7..1b38860aef443 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -310,9 +310,6 @@ fn lint_nan<'tcx>( deref_count += 1; ty = inner; } - if !matches!(*ty.kind(), ty::Float(fty) if fty == float_ty) { - return InvalidNanComparisonsSuggestion::Spanless; - } let neg = if is_ne { "!" } else { "" }; let Some(method_path) = nan_method_path(cx, nan, float_ty, cmp.span) else { return InvalidNanComparisonsSuggestion::Spanless; @@ -331,24 +328,26 @@ fn lint_nan<'tcx>( } } - let l_nan = nan_ty(cx, l); - let r_nan = nan_ty(cx, r); - let is_ne = binop == hir::BinOpKind::Ne; + let Some((value, nan, float_ty)) = nan_ty(cx, l) + .map(|float_ty| (r, l, float_ty)) + .or_else(|| nan_ty(cx, r).map(|float_ty| (l, r, float_ty))) + else { + return; + }; + let typeck_results = cx.typeck_results(); + // Custom comparison implementations need not follow primitive float NaN semantics. + if ![l, r].into_iter().all(|operand| { + typeck_results + .expr_ty_opt(operand) + .is_some_and(|ty| matches!(*ty.peel_refs().kind(), ty::Float(fty) if fty == float_ty)) + }) { + return; + } let lint = match binop { - hir::BinOpKind::Eq | hir::BinOpKind::Ne => { - let Some((value, nan, float_ty)) = l_nan - .map(|float_ty| (r, l, float_ty)) - .or_else(|| r_nan.map(|float_ty| (l, r, float_ty))) - else { - return; - }; - InvalidNanComparisons::EqNe { - suggestion: eq_ne_suggestion(cx, e, value, nan, float_ty, is_ne), - } - } - hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge - if l_nan.is_some() || r_nan.is_some() => - { + hir::BinOpKind::Eq | hir::BinOpKind::Ne => InvalidNanComparisons::EqNe { + suggestion: eq_ne_suggestion(cx, e, value, nan, float_ty, binop == hir::BinOpKind::Ne), + }, + hir::BinOpKind::Lt | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge => { InvalidNanComparisons::LtLeGtGe } _ => return, diff --git a/tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs b/tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs new file mode 100644 index 0000000000000..ccdb7e0d31859 --- /dev/null +++ b/tests/ui/lint/invalid-nan-comparisons/custom-comparisons.rs @@ -0,0 +1,73 @@ +//@ check-pass + +#![deny(invalid_nan_comparisons)] + +use std::cmp::Ordering; + +struct NotFloat; + +impl PartialEq for NotFloat { + fn eq(&self, other: &f64) -> bool { + other.is_nan() + } +} + +impl PartialEq for f64 { + fn eq(&self, other: &NotFloat) -> bool { + other == self + } +} + +impl PartialOrd for NotFloat { + fn partial_cmp(&self, other: &f64) -> Option { + other.is_nan().then_some(Ordering::Equal) + } +} + +impl PartialOrd for f64 { + fn partial_cmp(&self, other: &NotFloat) -> Option { + other.partial_cmp(self).map(Ordering::reverse) + } +} + +fn main() { + let value = NotFloat; + let _ = value == f64::NAN; + let _ = value != f64::NAN; + let _ = value < f64::NAN; + let _ = value <= f64::NAN; + let _ = value > f64::NAN; + let _ = value >= f64::NAN; + + let _ = f64::NAN == value; + let _ = f64::NAN != value; + let _ = f64::NAN < value; + let _ = f64::NAN <= value; + let _ = f64::NAN > value; + let _ = f64::NAN >= value; + + let _ = &value == &f64::NAN; + let _ = &value != &f64::NAN; + let _ = &value < &f64::NAN; + let _ = &value <= &f64::NAN; + let _ = &value > &f64::NAN; + let _ = &value >= &f64::NAN; + + let _ = &f64::NAN == &value; + let _ = &f64::NAN != &value; + let _ = &f64::NAN < &value; + let _ = &f64::NAN <= &value; + let _ = &f64::NAN > &value; + let _ = &f64::NAN >= &value; + + generic(value); +} + +fn generic>(value: T) { + let _ = value == f64::NAN; + let _ = value != f64::NAN; + let _ = value < f64::NAN; + let _ = value <= f64::NAN; + let _ = value > f64::NAN; + let _ = value >= f64::NAN; +} diff --git a/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.rs b/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.rs deleted file mode 100644 index be3351916ddc4..0000000000000 --- a/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ check-pass - -struct NotFloat; - -impl PartialEq for NotFloat { - fn eq(&self, _: &f64) -> bool { - true - } -} - -impl PartialEq for f64 { - fn eq(&self, _: &NotFloat) -> bool { - true - } -} - -fn main() { - let value = NotFloat; - let _ = value == f64::NAN; - //~^ WARN incorrect NaN comparison - let _ = f64::NAN != value; - //~^ WARN incorrect NaN comparison - let _ = &value != &f64::NAN; - //~^ WARN incorrect NaN comparison -} diff --git a/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr b/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr deleted file mode 100644 index f0c914dccdce6..0000000000000 --- a/tests/ui/lint/invalid-nan-comparisons/custom-partial-eq.stderr +++ /dev/null @@ -1,27 +0,0 @@ -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/custom-partial-eq.rs:19:13 - | -LL | let _ = value == f64::NAN; - | ^^^^^^^^^^^^^^^^^ - | - = help: use the `is_nan` method instead - = note: `#[warn(invalid_nan_comparisons)]` on by default - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/custom-partial-eq.rs:21:13 - | -LL | let _ = f64::NAN != value; - | ^^^^^^^^^^^^^^^^^ - | - = help: use the `is_nan` method instead - -warning: incorrect NaN comparison, NaN cannot be directly compared to itself - --> $DIR/custom-partial-eq.rs:23:13 - | -LL | let _ = &value != &f64::NAN; - | ^^^^^^^^^^^^^^^^^^^ - | - = help: use the `is_nan` method instead - -warning: 3 warnings emitted - From 8735b14a347b534fea24bbababd5107fd0cd76cc Mon Sep 17 00:00:00 2001 From: ywxt Date: Tue, 20 Oct 2026 09:59:59 +0800 Subject: [PATCH 11/14] Improve bit permutation codegen --- library/core/src/num/imp/int_bits.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/imp/int_bits.rs b/library/core/src/num/imp/int_bits.rs index 2bc95e66e7ef6..dbb1a54fc59f6 100644 --- a/library/core/src/num/imp/int_bits.rs +++ b/library/core/src/num/imp/int_bits.rs @@ -115,7 +115,7 @@ macro_rules! uint_impl { // [0; n], [X; a], [0; n], [0; b] // q // [0; n], [0; a + n], [Y; b] // x ^= q // [0; n + n], [X; a], [0; b] // q >> n - // [0; n], [0; n], [X; a], [Y; b] // x ^= q << n + // [0; n], [0; n], [X; a], [Y; b] // x ^= q >> n // ``` // Only zeros are shifted out, satisfying the assumption // for the next group. @@ -123,9 +123,18 @@ macro_rules! uint_impl { // In effect, the upper run of data is swapped with the // group of `n` zeros below it. let q = x & masks[stage]; - x ^= q; - x ^= q >> n; + if cfg!(all(target_arch = "aarch64", target_feature = "neon")) && $U::BITS <= 64 + { + // `q >> n` has no set bits in common with `x ^ q`, so addition + // is equivalent to XOR here. For widths up to 64 bits this + // allows AArch64 to use `usra`. For `u128`, this add may introduce + // a slower cross-limb carry chain. + x = (x & !masks[stage]).wrapping_add(q >> n); + } else { + x ^= q; + x ^= q >> n; + } stage += 1; } x From fcc7978927a59206f94a8848565ff3afee4e10cd Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 20 Oct 2026 09:22:39 +0200 Subject: [PATCH 12/14] Don't distinguish diagnostic kinds without special treatment Merge the PGO, Unsupported into UnknownDiagnostic and rename it to Other. We don't do anything special for them, so there is no need to represent them differently. --- compiler/rustc_codegen_llvm/src/back/write.rs | 4 +--- compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs | 10 +++------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 7abf0789658b1..922cf2fcfc9e6 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -486,9 +486,7 @@ fn diagnostic_handler_callback_inner( .expect("non-UTF8 diagnostic"); dcx.emit_warn(FromLlvmDiag { message }); } - llvm::diagnostic::PGO(diagnostic_ref) - | llvm::diagnostic::Unsupported(diagnostic_ref) - | llvm::diagnostic::UnknownDiagnostic(diagnostic_ref) => { + llvm::diagnostic::Other(diagnostic_ref) => { let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index e65f1e9d9f890..a5230595b7507 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -157,12 +157,10 @@ impl InlineAsmDiagnostic { pub(crate) enum Diagnostic<'ll> { Optimization(OptimizationDiagnostic<'ll>), InlineAsm(InlineAsmDiagnostic), - PGO(&'ll DiagnosticInfo), Linker(&'ll DiagnosticInfo), - Unsupported(&'ll DiagnosticInfo), - /// LLVM has other types that we do not wrap here. - UnknownDiagnostic(&'ll DiagnosticInfo), + /// LLVM has other types that we do not distinguish here. + Other(&'ll DiagnosticInfo), } impl<'ll> Diagnostic<'ll> { @@ -200,13 +198,11 @@ impl<'ll> Diagnostic<'ll> { Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) } - Dk::PGOProfile => PGO(di), Dk::Linker => Linker(di), - Dk::Unsupported => Unsupported(di), Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), - _ => UnknownDiagnostic(di), + _ => Other(di), } } } From b95ad06d4fb24dd1fb011323e4802b5b36400c3d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 20 Oct 2026 09:28:20 +0200 Subject: [PATCH 13/14] Don't downgrade linker error to warning --- compiler/rustc_codegen_llvm/src/back/write.rs | 8 +------- compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs | 3 --- tests/ui/lto/lto-duplicate-symbols.rs | 3 +-- tests/ui/lto/lto-duplicate-symbols.stderr | 6 ++---- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 922cf2fcfc9e6..27760dd7ea504 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -479,13 +479,7 @@ fn diagnostic_handler_callback_inner( message: &opt.message, }); } - llvm::diagnostic::Linker(diagnostic_ref) => { - let message = llvm::build_string(|s| unsafe { - llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) - }) - .expect("non-UTF8 diagnostic"); - dcx.emit_warn(FromLlvmDiag { message }); - } + llvm::diagnostic::Other(diagnostic_ref) => { let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index a5230595b7507..74cac217837d7 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -157,7 +157,6 @@ impl InlineAsmDiagnostic { pub(crate) enum Diagnostic<'ll> { Optimization(OptimizationDiagnostic<'ll>), InlineAsm(InlineAsmDiagnostic), - Linker(&'ll DiagnosticInfo), /// LLVM has other types that we do not distinguish here. Other(&'ll DiagnosticInfo), @@ -198,8 +197,6 @@ impl<'ll> Diagnostic<'ll> { Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) } - Dk::Linker => Linker(di), - Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), _ => Other(di), diff --git a/tests/ui/lto/lto-duplicate-symbols.rs b/tests/ui/lto/lto-duplicate-symbols.rs index 08465eb0fb27a..e468fbe4f30a4 100644 --- a/tests/ui/lto/lto-duplicate-symbols.rs +++ b/tests/ui/lto/lto-duplicate-symbols.rs @@ -10,5 +10,4 @@ extern crate lto_duplicate_symbols2; fn main() {} -//~? WARN Linking globals named 'foo': symbol multiply defined -//~? ERROR failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2 +//~? ERROR Linking globals named 'foo': symbol multiply defined diff --git a/tests/ui/lto/lto-duplicate-symbols.stderr b/tests/ui/lto/lto-duplicate-symbols.stderr index 7e421845258a3..0520ac3dee1f7 100644 --- a/tests/ui/lto/lto-duplicate-symbols.stderr +++ b/tests/ui/lto/lto-duplicate-symbols.stderr @@ -1,6 +1,4 @@ -warning: Linking globals named 'foo': symbol multiply defined! +error: Linking globals named 'foo': symbol multiply defined! -error: failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o": - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error From 03704177f51ea14794de54a991a702413a5b3b47 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Tue, 20 Oct 2026 04:01:22 -0500 Subject: [PATCH 14/14] emit usize and isize as typedefs --- .../src/debuginfo/metadata.rs | 46 ++++++++++++++++++- tests/codegen-llvm/debug-vtable.rs | 2 +- .../basic-types/lldb_input/non_windows.json | 4 +- .../basic-types/lldb_input/windows_gnu.json | 6 +-- .../pretty-std/lldb_input/non_windows.json | 15 ++++-- .../pretty-std/lldb_input/windows_gnu.json | 4 +- tests/debuginfo/rc_arc.rs | 10 ++++ 7 files changed, 72 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 60a29e5c73b16..87e0612bc102d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -6,6 +6,7 @@ use std::{assert_matches, iter, ptr}; use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Endian, Layout, NumScalableVectors, Size}; +use rustc_ast::{IntTy, UintTy}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; use rustc_hir::def::{CtorKind, DefKind}; @@ -794,9 +795,50 @@ fn build_basic_type_di_node<'ll, 'tcx>( _ => bug!("debuginfo::build_basic_type_di_node - `t` is invalid type"), }; - let ty_di_node = create_basic_type(cx, name, cx.size_of(t), encoding); + // Around LLDB 21 or 22, LLDB started using prebuilt Clang type nodes for primitives rather than + // reading the full DWARF data. These nodes are based on the size and signedness of the + // primitive, and ignore pretty much all other fields. This causes 2 issues: + // 1. type names get normalized to C-style names which isn't ideal. The normalization occurs + // even in generic args. + // 2. if you have a generic type `S`, and 2 instantiations are `S` + // and `S` (on a 64-bit target), the use of prebuilt nodes causes a name collision. + // Whichever instantiation is interacted with first will work fine, all others will break a + // bunch of stuff in the LLDB pipeline. To avoid this, we explicitly treat `usize` and `isize` + // as typedefs of their equivalent types. For more info see: llvm/llvm-project#196812 + + let mut needs_typedef = cpp_like_debuginfo; + + let ty_di_node = match t.kind() { + ty::Uint(UintTy::Usize) => { + needs_typedef = true; + + let equivalent = match t.primitive_size(cx.tcx).bits() { + 8 => cx.tcx.types.u8, + 16 => cx.tcx.types.u16, + 32 => cx.tcx.types.u32, + 64 => cx.tcx.types.u64, + 128 => cx.tcx.types.u128, + x => bug!("Unexpected signed int size {x}"), + }; + type_di_node(cx, equivalent) + } + ty::Int(IntTy::Isize) => { + needs_typedef = true; + + let equivalent = match t.primitive_size(cx.tcx).bits() { + 8 => cx.tcx.types.i8, + 16 => cx.tcx.types.i16, + 32 => cx.tcx.types.i32, + 64 => cx.tcx.types.i64, + 128 => cx.tcx.types.i128, + x => bug!("Unexpected signed int size: {x}"), + }; + type_di_node(cx, equivalent) + } + _ => create_basic_type(cx, name, cx.size_of(t), encoding), + }; - if !cpp_like_debuginfo { + if !needs_typedef { return DINodeCreationResult::new(ty_di_node, false); } diff --git a/tests/codegen-llvm/debug-vtable.rs b/tests/codegen-llvm/debug-vtable.rs index 8a7b1cc3c4bcc..031153832629c 100644 --- a/tests/codegen-llvm/debug-vtable.rs +++ b/tests/codegen-llvm/debug-vtable.rs @@ -19,7 +19,7 @@ // CHECK: @vtable.3 = private constant <{ // CHECK: @vtable.4 = private constant <{ -// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize" +// NONMSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" // MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" // NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()" // MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >" diff --git a/tests/debuginfo/basic-types/lldb_input/non_windows.json b/tests/debuginfo/basic-types/lldb_input/non_windows.json index af225246e6109..67c45674981a2 100644 --- a/tests/debuginfo/basic-types/lldb_input/non_windows.json +++ b/tests/debuginfo/basic-types/lldb_input/non_windows.json @@ -12,7 +12,7 @@ "value": false }, "i": { - "type": "long", + "type": "isize", "pretty_print": "-1", "value": -1 }, @@ -43,7 +43,7 @@ "value": -64 }, "u": { - "type": "unsigned long", + "type": "usize", "pretty_print": "1", "value": 1 }, diff --git a/tests/debuginfo/basic-types/lldb_input/windows_gnu.json b/tests/debuginfo/basic-types/lldb_input/windows_gnu.json index 80c35ffcbea60..06b21d7cb0b35 100644 --- a/tests/debuginfo/basic-types/lldb_input/windows_gnu.json +++ b/tests/debuginfo/basic-types/lldb_input/windows_gnu.json @@ -1,7 +1,7 @@ { "bless_metadata": { "python_version": "3.11.9 (tags/v3.11.9:de54cf5, Apr 2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)]", - "debugger_version": "lldb version 22.1.2 (https://github.com/llvm/llvm-project revision 1ab49a973e210e97d61e5db6557180dcb92c3e98)\n clang revision 1ab49a973e210e97d61e5db6557180dcb92c3e98\n llvm revision 1ab49a973e210e97d61e5db6557180dcb92c3e98", + "debugger_version": "lldb version 22.1.8 (https://github.com/llvm/llvm-project revision ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)\n clang revision ca7933e47d3a3451d81e72ac174dcb5aa28b59d1\n llvm revision ca7933e47d3a3451d81e72ac174dcb5aa28b59d1", "feature_flags": "LLDBFeature.StaticFields|TypeRecognizers|Float128" }, "breakpoints": [ @@ -12,7 +12,7 @@ "value": false }, "i": { - "type": "long long", + "type": "isize", "pretty_print": "-1", "value": -1 }, @@ -43,7 +43,7 @@ "value": -64 }, "u": { - "type": "unsigned long long", + "type": "usize", "pretty_print": "1", "value": 1 }, diff --git a/tests/debuginfo/pretty-std/lldb_input/non_windows.json b/tests/debuginfo/pretty-std/lldb_input/non_windows.json index 737eb5004b2bf..f76ba1ded06a1 100644 --- a/tests/debuginfo/pretty-std/lldb_input/non_windows.json +++ b/tests/debuginfo/pretty-std/lldb_input/non_windows.json @@ -162,7 +162,7 @@ }, { "name": "length", - "type": "unsigned long", + "type": "usize", "offset": 8 } ] @@ -178,7 +178,7 @@ }, { "name": "length", - "type": "unsigned long", + "type": "usize", "offset": 8 } ] @@ -273,7 +273,7 @@ }, { "name": "len", - "type": "unsigned long", + "type": "usize", "offset": 16 } ], @@ -293,7 +293,7 @@ }, { "name": "len", - "type": "unsigned long", + "type": "usize", "offset": 16 } ], @@ -322,7 +322,7 @@ "fields": [ { "name": "__0", - "type": "unsigned long", + "type": "usize", "offset": 0 } ] @@ -560,6 +560,11 @@ "size": 2, "type_class": 4, "basic_type": 12 + }, + "usize": { + "size": 8, + "type_class": 32768, + "basic_type": 16 } } } diff --git a/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json b/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json index 7f7772bd4caa1..56bfb83deef32 100644 --- a/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json +++ b/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json @@ -173,7 +173,7 @@ }, { "name": "length", - "type": "unsigned long long", + "type": "usize", "offset": 8 } ] @@ -284,7 +284,7 @@ }, { "name": "len", - "type": "unsigned long long", + "type": "usize", "offset": 16 } ], diff --git a/tests/debuginfo/rc_arc.rs b/tests/debuginfo/rc_arc.rs index adeb96dba1b80..e1af1eba02193 100644 --- a/tests/debuginfo/rc_arc.rs +++ b/tests/debuginfo/rc_arc.rs @@ -21,6 +21,11 @@ //@ lldb-check:[...] strong=11, weak=2 { value = 111 } //@ lldb-command:v arc //@ lldb-check:[...] strong=21, weak=2 { data = 222 } +//@ lldb-command:continue +//@ lldb-command:v rc_u64 +//@ lldb-check:[...] rc_u64 = strong=1, weak=1 { value = 10 } +//@ lldb-command:v rc_usize +//@ lldb-check:[...] rc_usize = strong=1, weak=1 { value = 20 } // === CDB TESTS ================================================================================== @@ -132,6 +137,11 @@ fn main() { let slice_arc_weak = Arc::downgrade(&slice_arc); zzz(); // #break + + let rc_u64 = Rc::new(10u64); + let rc_usize = Rc::new(20usize); + + zzz(); // #break } fn inc_ref_count(rc: &T, count: usize) {