rust-lang / rust-lang/rust-clippy

lint against float -> int casting

Open
#14,356 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-lint
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

What it does

Using the as keyword to cast between numeric types is hazardous, and is already covered by cast_sign_loss, cast_possible_truncation, and cast_possible_wrap.

Casting between integer types, though it may not be wise, at least has easy to remember semantics: when casting to a smaller type, it truncates, and when casting between signed/unsigned, it reinterprets the bits (possibly leading to under/overflow).
(reference)

Casting from floating point to integer has different behavior, comes with additional hazards, and needs extra weird semantics to cover special cases:

  • NaNs are converted to 0.
  • Out-of-range inputs (including +/- infinity) are saturated to the destination type's min/max values.
  • Fractional numbers are rounded toward zero.

This produces some surprising results:

  • -1.0 as u32 is 0
  • f32::NAN as i32 is 0
  • 1e20 as u32 is 4294967295. (value is shrunk by 10 orders of magnitude)

This leaves me wondering if there should be a clippy lint that only targets as casting from floating-point to integer.

Advantage

This might be helpful for codebases where integer->integer casts are just too common to warn against.

Drawbacks

Arguments against such a lint include:

  1. All cases are already covered by the cast_sign_loss and cast_possible_truncation lints, which also catch integer casts that may fail. Maybe it's silly to treat floating point inputs as special.
  2. There isn't one obvious fix to suggest. The standard library doesn't offer fallible conversions for NaN and out-of-range inputs. There are crates that can help: num_traits::NumCast has fallible conversions; conv2 has fallible conversions plus saturating, wrapping, rounding modes, etc.
Example
let x = some_float as u32;

Could be written as:

use conv2::ConvUtil;

let x = some_float.approx_as::<u32>().expect("input out of range");

or

use num_traits::NumCast;

let x: u32 = NumCast::from(x).expect("input out of range");

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by comparing the proposed lint with cast_sign_loss, cast_possible_truncation, and cast_possible_wrap, then review the linked Rust numeric-cast reference. Determine whether float-to-integer casts need distinct treatment and what behavior should be covered; done means the scope and rationale are resolved before implementation.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.