Skip to content

Commit

Permalink
casting integer literal to float is unnecessary
Browse files Browse the repository at this point in the history
  • Loading branch information
rink1969 committed Mar 14, 2019
1 parent 8fc0a73 commit d9dd008
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 135 deletions.
30 changes: 29 additions & 1 deletion clippy_lints/src/types.rs
Expand Up @@ -10,7 +10,7 @@ use rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisito
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::layout::LayoutOf;
use rustc::ty::{self, Ty, TyCtxt, TypeckTables};
use rustc::ty::{self, InferTy, Ty, TyCtxt, TypeckTables};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use rustc_target::spec::abi::Abi;
Expand Down Expand Up @@ -1150,13 +1150,41 @@ fn is_c_void(tcx: TyCtxt<'_, '_, '_>, ty: Ty<'_>) -> bool {
false
}

/// Returns the mantissa bits wide of a fp type.
/// Will return 0 if the type is not a fp
fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
match typ.sty {
ty::Float(FloatTy::F32) => 23,
ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
_ => 0,
}
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprKind::Cast(ref ex, _) = expr.node {
let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
if let ExprKind::Lit(ref lit) = ex.node {
use syntax::ast::{LitIntType, LitKind};
if let LitKind::Int(n, _) = lit.node {
if cast_to.is_fp() {
let from_nbits = 128 - n.leading_zeros();
let to_nbits = fp_ty_mantissa_nbits(cast_to);
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits {
span_lint_and_sugg(
cx,
UNNECESSARY_CAST,
expr.span,
&format!("casting integer literal to {} is unnecessary", cast_to),
"try",
format!("{}_{}", n, cast_to),
Applicability::MachineApplicable,
);
return;
}
}
}
match lit.node {
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::FloatUnsuffixed(_) => {},
_ => {
Expand Down
20 changes: 14 additions & 6 deletions tests/ui/cast.rs
Expand Up @@ -8,12 +8,16 @@
#[allow(clippy::no_effect, clippy::unnecessary_operation)]
fn main() {
// Test clippy::cast_precision_loss
1i32 as f32;
1i64 as f32;
1i64 as f64;
1u32 as f32;
1u64 as f32;
1u64 as f64;
let x0 = 1i32;
x0 as f32;
let x1 = 1i64;
x1 as f32;
x1 as f64;
let x2 = 1u32;
x2 as f32;
let x3 = 1u64;
x3 as f32;
x3 as f64;
// Test clippy::cast_possible_truncation
1f32 as i32;
1f32 as u32;
Expand Down Expand Up @@ -49,6 +53,10 @@ fn main() {
1f32 as f32;
false as bool;
&1i32 as &i32;
// casting integer literal to float is unnecessary
100 as f32;
100 as f64;
100_i32 as f64;
// Should not trigger
#[rustfmt::skip]
let v = vec!(1);
Expand Down
98 changes: 58 additions & 40 deletions tests/ui/cast.stderr
@@ -1,176 +1,194 @@
error: casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast.rs:11:5
--> $DIR/cast.rs:12:5
|
LL | 1i32 as f32;
| ^^^^^^^^^^^
LL | x0 as f32;
| ^^^^^^^^^
|
= note: `-D clippy::cast-precision-loss` implied by `-D warnings`

error: casting i64 to f32 causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast.rs:12:5
--> $DIR/cast.rs:14:5
|
LL | 1i64 as f32;
| ^^^^^^^^^^^
LL | x1 as f32;
| ^^^^^^^^^

error: casting i64 to f64 causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
--> $DIR/cast.rs:13:5
--> $DIR/cast.rs:15:5
|
LL | 1i64 as f64;
| ^^^^^^^^^^^
LL | x1 as f64;
| ^^^^^^^^^

error: casting u32 to f32 causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast.rs:14:5
--> $DIR/cast.rs:17:5
|
LL | 1u32 as f32;
| ^^^^^^^^^^^
LL | x2 as f32;
| ^^^^^^^^^

error: casting u64 to f32 causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast.rs:15:5
--> $DIR/cast.rs:19:5
|
LL | 1u64 as f32;
| ^^^^^^^^^^^
LL | x3 as f32;
| ^^^^^^^^^

error: casting u64 to f64 causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
--> $DIR/cast.rs:16:5
--> $DIR/cast.rs:20:5
|
LL | 1u64 as f64;
| ^^^^^^^^^^^
LL | x3 as f64;
| ^^^^^^^^^

error: casting f32 to i32 may truncate the value
--> $DIR/cast.rs:18:5
--> $DIR/cast.rs:22:5
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
|
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`

error: casting f32 to u32 may truncate the value
--> $DIR/cast.rs:19:5
--> $DIR/cast.rs:23:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^

error: casting f32 to u32 may lose the sign of the value
--> $DIR/cast.rs:19:5
--> $DIR/cast.rs:23:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
|
= note: `-D clippy::cast-sign-loss` implied by `-D warnings`

error: casting f64 to f32 may truncate the value
--> $DIR/cast.rs:20:5
--> $DIR/cast.rs:24:5
|
LL | 1f64 as f32;
| ^^^^^^^^^^^

error: casting i32 to i8 may truncate the value
--> $DIR/cast.rs:21:5
--> $DIR/cast.rs:25:5
|
LL | 1i32 as i8;
| ^^^^^^^^^^

error: casting i32 to u8 may truncate the value
--> $DIR/cast.rs:22:5
--> $DIR/cast.rs:26:5
|
LL | 1i32 as u8;
| ^^^^^^^^^^

error: casting f64 to isize may truncate the value
--> $DIR/cast.rs:23:5
--> $DIR/cast.rs:27:5
|
LL | 1f64 as isize;
| ^^^^^^^^^^^^^

error: casting f64 to usize may truncate the value
--> $DIR/cast.rs:24:5
--> $DIR/cast.rs:28:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^

error: casting f64 to usize may lose the sign of the value
--> $DIR/cast.rs:24:5
--> $DIR/cast.rs:28:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^

error: casting u8 to i8 may wrap around the value
--> $DIR/cast.rs:26:5
--> $DIR/cast.rs:30:5
|
LL | 1u8 as i8;
| ^^^^^^^^^
|
= note: `-D clippy::cast-possible-wrap` implied by `-D warnings`

error: casting u16 to i16 may wrap around the value
--> $DIR/cast.rs:27:5
--> $DIR/cast.rs:31:5
|
LL | 1u16 as i16;
| ^^^^^^^^^^^

error: casting u32 to i32 may wrap around the value
--> $DIR/cast.rs:28:5
--> $DIR/cast.rs:32:5
|
LL | 1u32 as i32;
| ^^^^^^^^^^^

error: casting u64 to i64 may wrap around the value
--> $DIR/cast.rs:29:5
--> $DIR/cast.rs:33:5
|
LL | 1u64 as i64;
| ^^^^^^^^^^^

error: casting usize to isize may wrap around the value
--> $DIR/cast.rs:30:5
--> $DIR/cast.rs:34:5
|
LL | 1usize as isize;
| ^^^^^^^^^^^^^^^

error: casting f32 to f64 may become silently lossy if types change
--> $DIR/cast.rs:32:5
--> $DIR/cast.rs:36:5
|
LL | 1.0f32 as f64;
| ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
|
= note: `-D clippy::cast-lossless` implied by `-D warnings`

error: casting u8 to u16 may become silently lossy if types change
--> $DIR/cast.rs:34:5
--> $DIR/cast.rs:38:5
|
LL | (1u8 + 1u8) as u16;
| ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)`

error: casting i32 to u32 may lose the sign of the value
--> $DIR/cast.rs:37:5
--> $DIR/cast.rs:41:5
|
LL | -1i32 as u32;
| ^^^^^^^^^^^^

error: casting isize to usize may lose the sign of the value
--> $DIR/cast.rs:39:5
--> $DIR/cast.rs:43:5
|
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^

error: casting to the same type is unnecessary (`i32` -> `i32`)
--> $DIR/cast.rs:48:5
--> $DIR/cast.rs:52:5
|
LL | 1i32 as i32;
| ^^^^^^^^^^^
|
= note: `-D clippy::unnecessary-cast` implied by `-D warnings`

error: casting to the same type is unnecessary (`f32` -> `f32`)
--> $DIR/cast.rs:49:5
--> $DIR/cast.rs:53:5
|
LL | 1f32 as f32;
| ^^^^^^^^^^^

error: casting to the same type is unnecessary (`bool` -> `bool`)
--> $DIR/cast.rs:50:5
--> $DIR/cast.rs:54:5
|
LL | false as bool;
| ^^^^^^^^^^^^^

error: aborting due to 27 previous errors
error: casting integer literal to f32 is unnecessary
--> $DIR/cast.rs:57:5
|
LL | 100 as f32;
| ^^^^^^^^^^ help: try: `100_f32`

error: casting integer literal to f64 is unnecessary
--> $DIR/cast.rs:58:5
|
LL | 100 as f64;
| ^^^^^^^^^^ help: try: `100_f64`

error: casting integer literal to f64 is unnecessary
--> $DIR/cast.rs:59:5
|
LL | 100_i32 as f64;
| ^^^^^^^^^^^^^^ help: try: `100_f64`

error: aborting due to 30 previous errors

26 changes: 16 additions & 10 deletions tests/ui/cast_lossless_float.fixed
Expand Up @@ -5,16 +5,22 @@

fn main() {
// Test clippy::cast_lossless with casts to floating-point types
f32::from(1i8);
f64::from(1i8);
f32::from(1u8);
f64::from(1u8);
f32::from(1i16);
f64::from(1i16);
f32::from(1u16);
f64::from(1u16);
f64::from(1i32);
f64::from(1u32);
let x0 = 1i8;
f32::from(x0);
f64::from(x0);
let x1 = 1u8;
f32::from(x1);
f64::from(x1);
let x2 = 1i16;
f32::from(x2);
f64::from(x2);
let x3 = 1u16;
f32::from(x3);
f64::from(x3);
let x4 = 1i32;
f64::from(x4);
let x5 = 1u32;
f64::from(x5);
}

// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
Expand Down
26 changes: 16 additions & 10 deletions tests/ui/cast_lossless_float.rs
Expand Up @@ -5,16 +5,22 @@

fn main() {
// Test clippy::cast_lossless with casts to floating-point types
1i8 as f32;
1i8 as f64;
1u8 as f32;
1u8 as f64;
1i16 as f32;
1i16 as f64;
1u16 as f32;
1u16 as f64;
1i32 as f64;
1u32 as f64;
let x0 = 1i8;
x0 as f32;
x0 as f64;
let x1 = 1u8;
x1 as f32;
x1 as f64;
let x2 = 1i16;
x2 as f32;
x2 as f64;
let x3 = 1u16;
x3 as f32;
x3 as f64;
let x4 = 1i32;
x4 as f64;
let x5 = 1u32;
x5 as f64;
}

// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
Expand Down

0 comments on commit d9dd008

Please sign in to comment.