From 24ab207671b0ac61c3b2008f9557a56cd4191efc Mon Sep 17 00:00:00 2001 From: Victor Korkin Date: Fri, 1 Jun 2018 23:08:11 +0700 Subject: [PATCH] Divide FN_TO_NUMERIC lint into two. FN_TO_NUMERIC_CAST_WITH_TRUNCATION is correctness check FN_TO_NUMERIC_CAST is only style check --- clippy_lints/src/types.rs | 56 ++++++++++++++++++++++------ tests/ui/types_fn_to_int.rs | 14 +++++-- tests/ui/types_fn_to_int.stderr | 66 +++++++++++++++++++++++++++------ 3 files changed, 109 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 0fe5f24f8d4..c309503ee38 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -679,9 +679,9 @@ declare_clippy_lint! { "cast to the same type, e.g. `x as i32` where `x: i32`" } -/// **What it does:** Checks for casts of a function pointer to a numeric type except `usize`. +/// **What it does:** Checks for casts of a function pointer to a numeric type not enough to store address. /// -/// **Why is this bad?** Casting a function pointer to something other than `usize` could truncate the address value. +/// **Why is this bad?** Casting a function pointer to not eligable type could truncate the address value. /// /// **Known problems:** None. /// @@ -691,8 +691,25 @@ declare_clippy_lint! { /// let _ = test_fn as i32 /// ``` declare_clippy_lint! { - pub FN_TO_NUMERIC_CAST, + pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION, correctness, + "cast function pointer to the numeric type with value truncation" +} + +/// **What it does:** Checks for casts of a function pointer to a numeric type except `usize`. +/// +/// **Why is this bad?** Casting a function pointer to something other than `usize` is not a good style. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// fn test_fn() -> i16; +/// let _ = test_fn as i128 +/// ``` +declare_clippy_lint! { + pub FN_TO_NUMERIC_CAST, + style, "cast function pointer to the numeric type" } @@ -909,7 +926,8 @@ impl LintPass for CastPass { CAST_LOSSLESS, UNNECESSARY_CAST, CAST_PTR_ALIGNMENT, - FN_TO_NUMERIC_CAST + FN_TO_NUMERIC_CAST, + FN_TO_NUMERIC_CAST_WITH_TRUNCATION, ) } } @@ -998,14 +1016,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { ty::TyFnDef(..) | ty::TyFnPtr(..) => { if cast_to.is_numeric() && cast_to.sty != ty::TyUint(UintTy::Usize){ - span_lint_and_sugg( - cx, - FN_TO_NUMERIC_CAST, - expr.span, - &format!("casting a `{}` to `{}` may truncate the function address value.", cast_from, cast_to), - "if you need the address of the function, consider", - format!("{} as usize", &snippet(cx, ex.span, "x")) - ); + let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); + let pointer_nbits = cx.tcx.data_layout.pointer_size.bits(); + if to_nbits < pointer_nbits || (to_nbits == pointer_nbits && cast_to.is_signed()) { + span_lint_and_sugg( + cx, + FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + expr.span, + &format!("casting a `{}` to `{}` may truncate the function address value.", cast_from, cast_to), + "if you need the address of the function, consider", + format!("{} as usize", &snippet(cx, ex.span, "x")) + ); + } else { + span_lint_and_sugg( + cx, + FN_TO_NUMERIC_CAST, + expr.span, + &format!("casting a `{}` to `{}` is bad style.", cast_from, cast_to), + "if you need the address of the function, consider", + format!("{} as usize", &snippet(cx, ex.span, "x")) + ); + + }; } } _ => () diff --git a/tests/ui/types_fn_to_int.rs b/tests/ui/types_fn_to_int.rs index 927f2149f30..8387586c3e9 100644 --- a/tests/ui/types_fn_to_int.rs +++ b/tests/ui/types_fn_to_int.rs @@ -9,8 +9,14 @@ fn bar() -> i32 { fn main() { let x = Foo::A; - let y = x as i32; - let y1 = Foo::A as i32; - - let z = bar as u32; + let _y = x as i32; + let _y1 = Foo::A as i32; + let _y = x as u32; + let _z = bar as u32; + let _y = bar as i64; + let _y = bar as u64; + let _z = Foo::A as i128; + let _z = Foo::A as u128; + let _z = bar as i128; + let _z = bar as u128; } diff --git a/tests/ui/types_fn_to_int.stderr b/tests/ui/types_fn_to_int.stderr index 0643230470d..bbdf4ce2e70 100644 --- a/tests/ui/types_fn_to_int.stderr +++ b/tests/ui/types_fn_to_int.stderr @@ -1,22 +1,66 @@ error: casting a `fn(usize) -> Foo {Foo::A}` to `i32` may truncate the function address value. - --> $DIR/types_fn_to_int.rs:12:13 + --> $DIR/types_fn_to_int.rs:12:14 | -12 | let y = x as i32; - | ^^^^^^^^ help: if you need the address of the function, consider: `x as usize` +12 | let _y = x as i32; + | ^^^^^^^^ help: if you need the address of the function, consider: `x as usize` | - = note: #[deny(fn_to_numeric_cast)] on by default + = note: #[deny(fn_to_numeric_cast_with_truncation)] on by default error: casting a `fn(usize) -> Foo {Foo::A}` to `i32` may truncate the function address value. - --> $DIR/types_fn_to_int.rs:13:14 + --> $DIR/types_fn_to_int.rs:13:15 | -13 | let y1 = Foo::A as i32; - | ^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize` +13 | let _y1 = Foo::A as i32; + | ^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize` + +error: casting a `fn(usize) -> Foo {Foo::A}` to `u32` may truncate the function address value. + --> $DIR/types_fn_to_int.rs:14:14 + | +14 | let _y = x as u32; + | ^^^^^^^^ help: if you need the address of the function, consider: `x as usize` error: casting a `fn() -> i32 {bar}` to `u32` may truncate the function address value. - --> $DIR/types_fn_to_int.rs:15:13 + --> $DIR/types_fn_to_int.rs:15:14 | -15 | let z = bar as u32; - | ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize` +15 | let _z = bar as u32; + | ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize` -error: aborting due to 3 previous errors +error: casting a `fn() -> i32 {bar}` to `i64` may truncate the function address value. + --> $DIR/types_fn_to_int.rs:16:14 + | +16 | let _y = bar as i64; + | ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize` + +error: casting a `fn() -> i32 {bar}` to `u64` is bad style. + --> $DIR/types_fn_to_int.rs:17:14 + | +17 | let _y = bar as u64; + | ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize` + | + = note: `-D fn-to-numeric-cast` implied by `-D warnings` + +error: casting a `fn(usize) -> Foo {Foo::A}` to `i128` is bad style. + --> $DIR/types_fn_to_int.rs:18:14 + | +18 | let _z = Foo::A as i128; + | ^^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize` + +error: casting a `fn(usize) -> Foo {Foo::A}` to `u128` is bad style. + --> $DIR/types_fn_to_int.rs:19:14 + | +19 | let _z = Foo::A as u128; + | ^^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize` + +error: casting a `fn() -> i32 {bar}` to `i128` is bad style. + --> $DIR/types_fn_to_int.rs:20:14 + | +20 | let _z = bar as i128; + | ^^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize` + +error: casting a `fn() -> i32 {bar}` to `u128` is bad style. + --> $DIR/types_fn_to_int.rs:21:14 + | +21 | let _z = bar as u128; + | ^^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize` + +error: aborting due to 10 previous errors