Skip to content

Commit f422721

Browse files
committed
Reimplement the fn_to_numeric_cast lint
1 parent 913a5c9 commit f422721

File tree

5 files changed

+98
-1
lines changed

5 files changed

+98
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ All notable changes to this project will be documented in this file.
688688
[`float_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_arithmetic
689689
[`float_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_cmp
690690
[`float_cmp_const`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_cmp_const
691+
[`fn_to_numeric_cast`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
691692
[`for_kv_map`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_kv_map
692693
[`for_loop_over_option`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_option
693694
[`for_loop_over_result`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_result

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ We are currently in the process of discussing Clippy 1.0 via the RFC process in
99

1010
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
1111

12-
[There are 277 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
12+
[There are 278 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
1313

1414
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1515

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
697697
types::CAST_LOSSLESS,
698698
types::CAST_PTR_ALIGNMENT,
699699
types::CHAR_LIT_AS_U8,
700+
types::FN_TO_NUMERIC_CAST,
700701
types::IMPLICIT_HASHER,
701702
types::LET_UNIT_VALUE,
702703
types::OPTION_OPTION,
@@ -789,6 +790,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
789790
returns::LET_AND_RETURN,
790791
returns::NEEDLESS_RETURN,
791792
strings::STRING_LIT_AS_BYTES,
793+
types::FN_TO_NUMERIC_CAST,
792794
types::IMPLICIT_HASHER,
793795
types::LET_UNIT_VALUE,
794796
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,

clippy_lints/src/types.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,30 @@ declare_clippy_lint! {
719719
"cast from a pointer to a more-strictly-aligned pointer"
720720
}
721721

722+
/// **What it does:** Checks for casts of function pointers to something other than usize
723+
///
724+
/// **Why is this bad?**
725+
/// Depending on the system architechture, casting a function pointer to something other than
726+
/// `usize` will result in incorrect pointer addresses.
727+
/// `usize` will always be able to store the function pointer on the given architechture.
728+
///
729+
/// **Example**
730+
///
731+
/// ```rust
732+
/// // Bad
733+
/// fn fun() -> i32 {}
734+
/// let a = fun as i64;
735+
///
736+
/// // Good
737+
/// fn fun2() -> i32 {}
738+
/// let a = fun2 as usize;
739+
/// ```
740+
declare_clippy_lint! {
741+
pub FN_TO_NUMERIC_CAST,
742+
style,
743+
"casting a function pointer to a numeric type other than usize"
744+
}
745+
722746
/// Returns the size in bits of an integral type.
723747
/// Will return 0 if the type is not an int or uint variant
724748
fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 {
@@ -913,6 +937,7 @@ impl LintPass for CastPass {
913937
CAST_LOSSLESS,
914938
UNNECESSARY_CAST,
915939
CAST_PTR_ALIGNMENT,
940+
FN_TO_NUMERIC_CAST
916941
)
917942
}
918943
}
@@ -921,6 +946,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
921946
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
922947
if let ExprKind::Cast(ref ex, _) = expr.node {
923948
let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
949+
lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
924950
if let ExprKind::Lit(ref lit) = ex.node {
925951
use crate::syntax::ast::{LitIntType, LitKind};
926952
match lit.node {
@@ -1021,6 +1047,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
10211047
}
10221048
}
10231049

1050+
fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Expr, cast_from: Ty, cast_to: Ty) {
1051+
match cast_from.sty {
1052+
ty::FnDef(..) | ty::FnPtr(_) => {
1053+
let from_snippet = snippet(cx, cast_expr.span, "x");
1054+
if cast_to.sty != ty::Uint(UintTy::Usize) {
1055+
span_lint_and_sugg(
1056+
cx,
1057+
FN_TO_NUMERIC_CAST,
1058+
expr.span,
1059+
&format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
1060+
"try",
1061+
format!("{} as usize", from_snippet)
1062+
);
1063+
}
1064+
},
1065+
_ => {}
1066+
}
1067+
}
1068+
10241069
/// **What it does:** Checks for types used in structs, parameters and `let`
10251070
/// declarations above a certain complexity threshold.
10261071
///

tests/ui/fn_to_numeric_cast.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#![feature(tool_lints)]
2+
3+
#[warn(clippy::fn_to_numeric_cast)]
4+
5+
fn foo() -> String { String::new() }
6+
7+
fn test_function_to_numeric_cast() {
8+
let _ = foo as i8;
9+
let _ = foo as i16;
10+
let _ = foo as i32;
11+
let _ = foo as i64;
12+
let _ = foo as i128;
13+
let _ = foo as isize;
14+
15+
let _ = foo as u8;
16+
let _ = foo as u16;
17+
let _ = foo as u32;
18+
let _ = foo as u64;
19+
let _ = foo as u128;
20+
21+
// Casting to usize is OK and should not warn
22+
let _ = foo as usize;
23+
}
24+
25+
fn test_function_var_to_numeric_cast() {
26+
let abc: fn() -> String = foo;
27+
28+
let _ = abc as i8;
29+
let _ = abc as i16;
30+
let _ = abc as i32;
31+
let _ = abc as i64;
32+
let _ = abc as i128;
33+
let _ = abc as isize;
34+
35+
let _ = abc as u8;
36+
let _ = abc as u16;
37+
let _ = abc as u32;
38+
let _ = abc as u64;
39+
let _ = abc as u128;
40+
41+
// Casting to usize is OK and should not warn
42+
let _ = abc as usize;
43+
}
44+
45+
fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
46+
f as i32
47+
}
48+
49+
fn main() {}

0 commit comments

Comments
 (0)