Skip to content

lint: suggest fXX::is_nan for unsuffixed NaN comparisons - #164264

Merged
rust-bors[bot] merged 7 commits into
rust-lang:mainfrom
caelyreth:fix-invalid-nan-float
Oct 21, 2026
Merged

rust-bors[bot] merged 7 commits into
rust-lang:mainfrom
caelyreth:fix-invalid-nan-float

Conversation

@caelyreth

@caelyreth caelyreth commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #164143

about this bug

invalid_nan_comparisons turned b != &f64::NAN into b.is_nan(). That is fine for something like 3.3f32 or let x: f64 = 3.3, but not for type unannotated let b = &3.3; the comparison is what makes {float} into f64, and after the edit .is_nan() does not resolve. Same for let mut.

lint behaviors after this fix

  • If the operand is a float, the suggestion is <Type>::is_nan(...), using the NAN constant's type and adding dereferences and parentheses as needed;
  • Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through std or core;
  • If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

.is_nan() can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. <Type>:: also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

  • help me find out what HIR or AST feature can be used to distinguish unsuffixed float
  • draft the initial naive fix reference before I hand written & review the code
  • help me improve the ui test case edge case coverage

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Oct 13, 2026
@rust-log-analyzer

This comment has been minimized.

@caelyreth
caelyreth marked this pull request as ready for review October 16, 2026 12:59
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 16, 2026
@rustbot

rustbot commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome! The Rust Project has assigned @jieyouxu (or someone else) to review your changes, you should hear from them (or someone else) within the next two weeks.

Please see the contribution instructions and our LLM policy for more information.

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 77 candidates
  • Random selection from 19 candidates

@jieyouxu jieyouxu left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Minor things
@rustbot author

View changes since this review

Comment thread tests/ui/lint/invalid-nan-comparison-custom-partial-eq.rs Outdated
Comment thread tests/ui/lint/invalid-nan-comparison-custom-partial-eq.stderr Outdated
Comment thread tests/ui/lint/invalid-nan-comparisons/suggestion.fixed
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 18, 2026
@rustbot

rustbot commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@caelyreth

Copy link
Copy Markdown
Contributor Author

Thank for your review!

Custom comparisons can define their own NaN behavior. The lint now requires matching primitive float types after peeling references, so custom PartialEq (and PartialOrd) comparisons receive neither the warning nor the help.

Regression tests cover both operand orders, references, and generic operands.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 19, 2026
@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job test-x86_64-gnu-next-trait-solver-polonius failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)

Important

For more information how to resolve CI failures of this job, visit this link.

@caelyreth

Copy link
Copy Markdown
Contributor Author

The CI was failed due to dependency fetching, @jieyouxu could you please rerun it or give me permission to retry?

@jieyouxu

Copy link
Copy Markdown
Member

Easiest way is to reopen the PR.

@jieyouxu jieyouxu closed this Oct 20, 2026
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 20, 2026
@jieyouxu jieyouxu reopened this Oct 20, 2026
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 20, 2026

@jieyouxu jieyouxu left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I don't love the unconditional UFCS, but at least the suggestion isn't outright invalid, which I think is a net improvement.

@bors r+ rollup

View changes since this review

rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 6 pull requests

Successful merges:

 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164578 (Don't ignore unknown LLVM diagnostics)
 - #164611 (Improve bit permutation codegen)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 20, 2026
…=jieyouxu

lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons

Fixes rust-lang#164143

### about this bug

`invalid_nan_comparisons` turned `b != &f64::NAN` into `b.is_nan()`. That is fine for something like `3.3f32` or `let x: f64 = 3.3`, but not for type unannotated `let b = &3.3`; the comparison is what makes `{float}` into `f64`, and after the edit `.is_nan()` does not resolve. Same for `let mut`.

### lint behaviors after this fix

- If the operand is a float, the suggestion is `<Type>::is_nan(...)`, using the NAN constant's type and adding dereferences and parentheses as needed;
- Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through `std` or `core`;
- If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

`.is_nan()` can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. `<Type>::` also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

### llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

- help me find out what HIR or AST feature can be used to distinguish unsuffixed float
- draft the initial naive fix reference before I hand written & review the code
- help me improve the ui test case edge case coverage
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 14 pull requests

Successful merges:

 - #163575 (core: Add examples and assembly tests for `abort_immediate`)
 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163338 (MIR move elimination [4/6]: MoveElimination)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164578 (Don't ignore unknown LLVM diagnostics)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 20, 2026
…=jieyouxu

lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons

Fixes rust-lang#164143

### about this bug

`invalid_nan_comparisons` turned `b != &f64::NAN` into `b.is_nan()`. That is fine for something like `3.3f32` or `let x: f64 = 3.3`, but not for type unannotated `let b = &3.3`; the comparison is what makes `{float}` into `f64`, and after the edit `.is_nan()` does not resolve. Same for `let mut`.

### lint behaviors after this fix

- If the operand is a float, the suggestion is `<Type>::is_nan(...)`, using the NAN constant's type and adding dereferences and parentheses as needed;
- Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through `std` or `core`;
- If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

`.is_nan()` can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. `<Type>::` also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

### llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

- help me find out what HIR or AST feature can be used to distinguish unsuffixed float
- draft the initial naive fix reference before I hand written & review the code
- help me improve the ui test case edge case coverage
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 13 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163338 (MIR move elimination [4/6]: MoveElimination)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164578 (Don't ignore unknown LLVM diagnostics)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 13 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163338 (MIR move elimination [4/6]: MoveElimination)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164578 (Don't ignore unknown LLVM diagnostics)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 20, 2026
…=jieyouxu

lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons

Fixes rust-lang#164143

### about this bug

`invalid_nan_comparisons` turned `b != &f64::NAN` into `b.is_nan()`. That is fine for something like `3.3f32` or `let x: f64 = 3.3`, but not for type unannotated `let b = &3.3`; the comparison is what makes `{float}` into `f64`, and after the edit `.is_nan()` does not resolve. Same for `let mut`.

### lint behaviors after this fix

- If the operand is a float, the suggestion is `<Type>::is_nan(...)`, using the NAN constant's type and adding dereferences and parentheses as needed;
- Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through `std` or `core`;
- If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

`.is_nan()` can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. `<Type>::` also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

### llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

- help me find out what HIR or AST feature can be used to distinguish unsuffixed float
- draft the initial naive fix reference before I hand written & review the code
- help me improve the ui test case edge case coverage
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 15 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163338 (MIR move elimination [4/6]: MoveElimination)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164540 (Minor optimizations around macro parsing)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164595 (Allow attributes in function trait parameters)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 20, 2026
…=jieyouxu

lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons

Fixes rust-lang#164143

### about this bug

`invalid_nan_comparisons` turned `b != &f64::NAN` into `b.is_nan()`. That is fine for something like `3.3f32` or `let x: f64 = 3.3`, but not for type unannotated `let b = &3.3`; the comparison is what makes `{float}` into `f64`, and after the edit `.is_nan()` does not resolve. Same for `let mut`.

### lint behaviors after this fix

- If the operand is a float, the suggestion is `<Type>::is_nan(...)`, using the NAN constant's type and adding dereferences and parentheses as needed;
- Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through `std` or `core`;
- If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

`.is_nan()` can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. `<Type>::` also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

### llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

- help me find out what HIR or AST feature can be used to distinguish unsuffixed float
- draft the initial naive fix reference before I hand written & review the code
- help me improve the ui test case edge case coverage
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 14 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164540 (Minor optimizations around macro parsing)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164595 (Allow attributes in function trait parameters)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 14 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164540 (Minor optimizations around macro parsing)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164595 (Allow attributes in function trait parameters)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 20, 2026
…=jieyouxu

lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons

Fixes rust-lang#164143

### about this bug

`invalid_nan_comparisons` turned `b != &f64::NAN` into `b.is_nan()`. That is fine for something like `3.3f32` or `let x: f64 = 3.3`, but not for type unannotated `let b = &3.3`; the comparison is what makes `{float}` into `f64`, and after the edit `.is_nan()` does not resolve. Same for `let mut`.

### lint behaviors after this fix

- If the operand is a float, the suggestion is `<Type>::is_nan(...)`, using the NAN constant's type and adding dereferences and parentheses as needed;
- Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through `std` or `core`;
- If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

`.is_nan()` can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. `<Type>::` also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

### llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

- help me find out what HIR or AST feature can be used to distinguish unsuffixed float
- draft the initial naive fix reference before I hand written & review the code
- help me improve the ui test case edge case coverage
rust-bors Bot pushed a commit that referenced this pull request Oct 20, 2026
…uwer

Rollup of 19 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - #160404 (fd-views: AsRef<File>&Co. for BorrowedFd)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164540 (Minor optimizations around macro parsing)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164595 (Allow attributes in function trait parameters)
 - #164641 (Stabilize `slice_split_once`)
 - #164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
rust-bors Bot pushed a commit that referenced this pull request Oct 21, 2026
Rollup of 20 pull requests

Successful merges:

 - #163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - #163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - #163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - #163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - #163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - #164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - #164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - #164611 (Improve bit permutation codegen)
 - #164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - #148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - #162668 (document that `!` does bitwise and logical negation)
 - #164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - #164509 (layout invariant: turn delayed bug back into proper assertion)
 - #164540 (Minor optimizations around macro parsing)
 - #164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - #164595 (Allow attributes in function trait parameters)
 - #164616 (Add test for VecDeque with a custom allocator)
 - #164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
 - #164641 (Stabilize `slice_split_once`)
 - #164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
@rust-bors
rust-bors Bot merged commit ddb54cc into rust-lang:main Oct 21, 2026
18 of 28 checks passed
@rustbot rustbot added this to the 1.101.0 milestone Oct 21, 2026
rust-bors Bot pushed a commit that referenced this pull request Oct 21, 2026
Rollup merge of #164264 - caelyreth:fix-invalid-nan-float, r=jieyouxu

lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons

Fixes #164143

### about this bug

`invalid_nan_comparisons` turned `b != &f64::NAN` into `b.is_nan()`. That is fine for something like `3.3f32` or `let x: f64 = 3.3`, but not for type unannotated `let b = &3.3`; the comparison is what makes `{float}` into `f64`, and after the edit `.is_nan()` does not resolve. Same for `let mut`.

### lint behaviors after this fix

- If the operand is a float, the suggestion is `<Type>::is_nan(...)`, using the NAN constant's type and adding dereferences and parentheses as needed;
- Preserve the original type path or alias. For macro-generated f32/f64 constants, use an absolute primitive path through `std` or `core`;
- If it is not a float, or a safe replacement cannot be constructed, only keep the help text.

I decide to use the type-qualified form even for suffixed or explicitly typed operands.

`.is_nan()` can work in those cases, but the resolved type alone does not tell us whether removing the comparison preserves inference.

Using one form avoids incomplete initializer heuristics. `<Type>::` also ensures the reused path is interpreted as a type, avoiding ambiguity with modules.

### llm disclosure

The LLM (specifically, Grok 4.7 and GPT 6.1 Sol) was used for:

- help me find out what HIR or AST feature can be used to distinguish unsuffixed float
- draft the initial naive fix reference before I hand written & review the code
- help me improve the ui test case edge case coverage
github-actions Bot pushed a commit to rust-lang/stdarch that referenced this pull request Oct 22, 2026
Rollup of 20 pull requests

Successful merges:

 - rust-lang/rust#163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - rust-lang/rust#163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - rust-lang/rust#163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - rust-lang/rust#163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - rust-lang/rust#163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - rust-lang/rust#164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - rust-lang/rust#164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - rust-lang/rust#164611 (Improve bit permutation codegen)
 - rust-lang/rust#164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - rust-lang/rust#148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - rust-lang/rust#162668 (document that `!` does bitwise and logical negation)
 - rust-lang/rust#164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - rust-lang/rust#164509 (layout invariant: turn delayed bug back into proper assertion)
 - rust-lang/rust#164540 (Minor optimizations around macro parsing)
 - rust-lang/rust#164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - rust-lang/rust#164595 (Allow attributes in function trait parameters)
 - rust-lang/rust#164616 (Add test for VecDeque with a custom allocator)
 - rust-lang/rust#164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
 - rust-lang/rust#164641 (Stabilize `slice_split_once`)
 - rust-lang/rust#164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
jieyouxu pushed a commit to jieyouxu/rustfmt that referenced this pull request Oct 22, 2026
Rollup of 20 pull requests

Successful merges:

 - rust-lang/rust#163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - rust-lang/rust#163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - rust-lang/rust#163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - rust-lang/rust#163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - rust-lang/rust#163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - rust-lang/rust#164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - rust-lang/rust#164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - rust-lang/rust#164611 (Improve bit permutation codegen)
 - rust-lang/rust#164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - rust-lang/rust#148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - rust-lang/rust#162668 (document that `!` does bitwise and logical negation)
 - rust-lang/rust#164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - rust-lang/rust#164509 (layout invariant: turn delayed bug back into proper assertion)
 - rust-lang/rust#164540 (Minor optimizations around macro parsing)
 - rust-lang/rust#164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - rust-lang/rust#164595 (Allow attributes in function trait parameters)
 - rust-lang/rust#164616 (Add test for VecDeque with a custom allocator)
 - rust-lang/rust#164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
 - rust-lang/rust#164641 (Stabilize `slice_split_once`)
 - rust-lang/rust#164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
programskillforverification pushed a commit to programskillforverification/miri that referenced this pull request Oct 22, 2026
Rollup of 20 pull requests

Successful merges:

 - rust-lang/rust#163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - rust-lang/rust#163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - rust-lang/rust#163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - rust-lang/rust#163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - rust-lang/rust#163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - rust-lang/rust#164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - rust-lang/rust#164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - rust-lang/rust#164611 (Improve bit permutation codegen)
 - rust-lang/rust#164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - rust-lang/rust#148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - rust-lang/rust#162668 (document that `!` does bitwise and logical negation)
 - rust-lang/rust#164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - rust-lang/rust#164509 (layout invariant: turn delayed bug back into proper assertion)
 - rust-lang/rust#164540 (Minor optimizations around macro parsing)
 - rust-lang/rust#164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - rust-lang/rust#164595 (Allow attributes in function trait parameters)
 - rust-lang/rust#164616 (Add test for VecDeque with a custom allocator)
 - rust-lang/rust#164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
 - rust-lang/rust#164641 (Stabilize `slice_split_once`)
 - rust-lang/rust#164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
bjorn3 pushed a commit to rust-lang/rustc_codegen_cranelift that referenced this pull request Oct 23, 2026
Rollup of 20 pull requests

Successful merges:

 - rust-lang/rust#163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - rust-lang/rust#163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - rust-lang/rust#163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - rust-lang/rust#163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - rust-lang/rust#163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - rust-lang/rust#164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - rust-lang/rust#164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - rust-lang/rust#164611 (Improve bit permutation codegen)
 - rust-lang/rust#164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - rust-lang/rust#148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - rust-lang/rust#162668 (document that `!` does bitwise and logical negation)
 - rust-lang/rust#164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - rust-lang/rust#164509 (layout invariant: turn delayed bug back into proper assertion)
 - rust-lang/rust#164540 (Minor optimizations around macro parsing)
 - rust-lang/rust#164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - rust-lang/rust#164595 (Allow attributes in function trait parameters)
 - rust-lang/rust#164616 (Add test for VecDeque with a custom allocator)
 - rust-lang/rust#164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
 - rust-lang/rust#164641 (Stabilize `slice_split_once`)
 - rust-lang/rust#164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
github-actions Bot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Oct 25, 2026
Rollup of 20 pull requests

Successful merges:

 - rust-lang/rust#163664 (Add new `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` mode for testing stable compiler behavior in UI tests)
 - rust-lang/rust#163668 (Remap syntax contexts and expansion ids for det. metadata encoding)
 - rust-lang/rust#163104 ([debuginfo] Emit `usize` and `isize` as typedefs)
 - rust-lang/rust#163317 (Stop useless caching of post-LTO artifact caching for fat LTO)
 - rust-lang/rust#163701 (add ReadDir::dir to get the directory handle of the underlying directory)
 - rust-lang/rust#164488 (Don't try to skip anything in `Skip::advance_by(0)`)
 - rust-lang/rust#164507 (Encode HashMap and HashSet in deterministic order when an encoder requires determinism)
 - rust-lang/rust#164611 (Improve bit permutation codegen)
 - rust-lang/rust#164612 (std: Combine `is_powerpc64_feature_detected` into `is_powerpc_feature_detected`)
 - rust-lang/rust#148842 (Avoid incorrect lifetime suggestion involving `sym::anon`)
 - rust-lang/rust#162668 (document that `!` does bitwise and logical negation)
 - rust-lang/rust#164264 (lint: suggest `fXX::is_nan` for unsuffixed NaN comparisons)
 - rust-lang/rust#164509 (layout invariant: turn delayed bug back into proper assertion)
 - rust-lang/rust#164540 (Minor optimizations around macro parsing)
 - rust-lang/rust#164594 (rustdoc: Correctly handle inner `deprecated` attribute on modules)
 - rust-lang/rust#164595 (Allow attributes in function trait parameters)
 - rust-lang/rust#164616 (Add test for VecDeque with a custom allocator)
 - rust-lang/rust#164629 (arch::breakpoint: avoid confusing 'equivalent' terminology)
 - rust-lang/rust#164641 (Stabilize `slice_split_once`)
 - rust-lang/rust#164646 (Adjust rustfmt subtree sync docs to not use `--allow-noop` for now)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

innvalid invalid_nan_comparisons breaks: no method named is_nan found for reference &{float}

4 participants