Skip to content

Commit c0ab8b2

Browse files
committed
Reimplement the fn_to_numeric_cast_with_truncation lint
1 parent 7adf24e commit c0ab8b2

File tree

8 files changed

+249
-3
lines changed

8 files changed

+249
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ All notable changes to this project will be documented in this file.
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
691691
[`fn_to_numeric_cast`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
692+
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
692693
[`for_kv_map`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_kv_map
693694
[`for_loop_over_option`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_option
694695
[`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 278 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
12+
[There are 279 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
@@ -698,6 +698,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
698698
types::CAST_PTR_ALIGNMENT,
699699
types::CHAR_LIT_AS_U8,
700700
types::FN_TO_NUMERIC_CAST,
701+
types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
701702
types::IMPLICIT_HASHER,
702703
types::LET_UNIT_VALUE,
703704
types::OPTION_OPTION,
@@ -791,6 +792,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
791792
returns::NEEDLESS_RETURN,
792793
strings::STRING_LIT_AS_BYTES,
793794
types::FN_TO_NUMERIC_CAST,
795+
types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
794796
types::IMPLICIT_HASHER,
795797
types::LET_UNIT_VALUE,
796798
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,

clippy_lints/src/types.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,32 @@ declare_clippy_lint! {
746746
"casting a function pointer to a numeric type other than usize"
747747
}
748748

749+
/// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to
750+
/// store address.
751+
///
752+
/// **Why is this bad?**
753+
/// Such a cast discards some bits of the function's address. If this is intended, it would be more
754+
/// clearly expressed by casting to usize first, then casting the usize to the intended type (with
755+
/// a comment) to perform the truncation.
756+
///
757+
/// **Example**
758+
///
759+
/// ```rust
760+
/// // Bad
761+
/// fn fn1() -> i16 { 1 };
762+
/// let _ = fn1 as i32;
763+
///
764+
/// // Better: Cast to usize first, then comment with the reason for the truncation
765+
/// fn fn2() -> i16 { 1 };
766+
/// let fn_ptr = fn2 as usize;
767+
/// let fn_ptr_truncated = fn_ptr as i32;
768+
/// ```
769+
declare_clippy_lint! {
770+
pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
771+
style,
772+
"casting a function pointer to a numeric type not wide enough to store the address"
773+
}
774+
749775
/// Returns the size in bits of an integral type.
750776
/// Will return 0 if the type is not an int or uint variant
751777
fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 {
@@ -1054,7 +1080,19 @@ fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Ex
10541080
match cast_from.sty {
10551081
ty::FnDef(..) | ty::FnPtr(_) => {
10561082
let from_snippet = snippet(cx, cast_expr.span, "x");
1057-
if cast_to.sty != ty::Uint(UintTy::Usize) {
1083+
1084+
let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
1085+
if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
1086+
span_lint_and_sugg(
1087+
cx,
1088+
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
1089+
expr.span,
1090+
&format!("casting function pointer `{}` to `{}`, which truncates the value", from_snippet, cast_to),
1091+
"try",
1092+
format!("{} as usize", from_snippet)
1093+
);
1094+
1095+
} else if cast_to.sty != ty::Uint(UintTy::Usize) {
10581096
span_lint_and_sugg(
10591097
cx,
10601098
FN_TO_NUMERIC_CAST,

tests/ui/fn_to_numeric_cast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(tool_lints)]
22

3-
#[warn(clippy::fn_to_numeric_cast)]
3+
#![warn(clippy::fn_to_numeric_cast)]
44

55
fn foo() -> String { String::new() }
66

tests/ui/fn_to_numeric_cast.stderr

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
error: casting function pointer `foo` to `i8`
2+
--> $DIR/fn_to_numeric_cast.rs:8:13
3+
|
4+
8 | let _ = foo as i8;
5+
| ^^^^^^^^^ help: try: `foo as usize`
6+
|
7+
= note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
8+
9+
error: casting function pointer `foo` to `i16`
10+
--> $DIR/fn_to_numeric_cast.rs:9:13
11+
|
12+
9 | let _ = foo as i16;
13+
| ^^^^^^^^^^ help: try: `foo as usize`
14+
15+
error: casting function pointer `foo` to `i32`
16+
--> $DIR/fn_to_numeric_cast.rs:10:13
17+
|
18+
10 | let _ = foo as i32;
19+
| ^^^^^^^^^^ help: try: `foo as usize`
20+
21+
error: casting function pointer `foo` to `i64`
22+
--> $DIR/fn_to_numeric_cast.rs:11:13
23+
|
24+
11 | let _ = foo as i64;
25+
| ^^^^^^^^^^ help: try: `foo as usize`
26+
27+
error: casting function pointer `foo` to `i128`
28+
--> $DIR/fn_to_numeric_cast.rs:12:13
29+
|
30+
12 | let _ = foo as i128;
31+
| ^^^^^^^^^^^ help: try: `foo as usize`
32+
33+
error: casting function pointer `foo` to `isize`
34+
--> $DIR/fn_to_numeric_cast.rs:13:13
35+
|
36+
13 | let _ = foo as isize;
37+
| ^^^^^^^^^^^^ help: try: `foo as usize`
38+
39+
error: casting function pointer `foo` to `u8`
40+
--> $DIR/fn_to_numeric_cast.rs:15:13
41+
|
42+
15 | let _ = foo as u8;
43+
| ^^^^^^^^^ help: try: `foo as usize`
44+
45+
error: casting function pointer `foo` to `u16`
46+
--> $DIR/fn_to_numeric_cast.rs:16:13
47+
|
48+
16 | let _ = foo as u16;
49+
| ^^^^^^^^^^ help: try: `foo as usize`
50+
51+
error: casting function pointer `foo` to `u32`
52+
--> $DIR/fn_to_numeric_cast.rs:17:13
53+
|
54+
17 | let _ = foo as u32;
55+
| ^^^^^^^^^^ help: try: `foo as usize`
56+
57+
error: casting function pointer `foo` to `u64`
58+
--> $DIR/fn_to_numeric_cast.rs:18:13
59+
|
60+
18 | let _ = foo as u64;
61+
| ^^^^^^^^^^ help: try: `foo as usize`
62+
63+
error: casting function pointer `foo` to `u128`
64+
--> $DIR/fn_to_numeric_cast.rs:19:13
65+
|
66+
19 | let _ = foo as u128;
67+
| ^^^^^^^^^^^ help: try: `foo as usize`
68+
69+
error: casting function pointer `abc` to `i8`
70+
--> $DIR/fn_to_numeric_cast.rs:28:13
71+
|
72+
28 | let _ = abc as i8;
73+
| ^^^^^^^^^ help: try: `abc as usize`
74+
75+
error: casting function pointer `abc` to `i16`
76+
--> $DIR/fn_to_numeric_cast.rs:29:13
77+
|
78+
29 | let _ = abc as i16;
79+
| ^^^^^^^^^^ help: try: `abc as usize`
80+
81+
error: casting function pointer `abc` to `i32`
82+
--> $DIR/fn_to_numeric_cast.rs:30:13
83+
|
84+
30 | let _ = abc as i32;
85+
| ^^^^^^^^^^ help: try: `abc as usize`
86+
87+
error: casting function pointer `abc` to `i64`
88+
--> $DIR/fn_to_numeric_cast.rs:31:13
89+
|
90+
31 | let _ = abc as i64;
91+
| ^^^^^^^^^^ help: try: `abc as usize`
92+
93+
error: casting function pointer `abc` to `i128`
94+
--> $DIR/fn_to_numeric_cast.rs:32:13
95+
|
96+
32 | let _ = abc as i128;
97+
| ^^^^^^^^^^^ help: try: `abc as usize`
98+
99+
error: casting function pointer `abc` to `isize`
100+
--> $DIR/fn_to_numeric_cast.rs:33:13
101+
|
102+
33 | let _ = abc as isize;
103+
| ^^^^^^^^^^^^ help: try: `abc as usize`
104+
105+
error: casting function pointer `abc` to `u8`
106+
--> $DIR/fn_to_numeric_cast.rs:35:13
107+
|
108+
35 | let _ = abc as u8;
109+
| ^^^^^^^^^ help: try: `abc as usize`
110+
111+
error: casting function pointer `abc` to `u16`
112+
--> $DIR/fn_to_numeric_cast.rs:36:13
113+
|
114+
36 | let _ = abc as u16;
115+
| ^^^^^^^^^^ help: try: `abc as usize`
116+
117+
error: casting function pointer `abc` to `u32`
118+
--> $DIR/fn_to_numeric_cast.rs:37:13
119+
|
120+
37 | let _ = abc as u32;
121+
| ^^^^^^^^^^ help: try: `abc as usize`
122+
123+
error: casting function pointer `abc` to `u64`
124+
--> $DIR/fn_to_numeric_cast.rs:38:13
125+
|
126+
38 | let _ = abc as u64;
127+
| ^^^^^^^^^^ help: try: `abc as usize`
128+
129+
error: casting function pointer `abc` to `u128`
130+
--> $DIR/fn_to_numeric_cast.rs:39:13
131+
|
132+
39 | let _ = abc as u128;
133+
| ^^^^^^^^^^^ help: try: `abc as usize`
134+
135+
error: casting function pointer `f` to `i32`
136+
--> $DIR/fn_to_numeric_cast.rs:46:5
137+
|
138+
46 | f as i32
139+
| ^^^^^^^^ help: try: `f as usize`
140+
141+
error: aborting due to 23 previous errors
142+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![feature(tool_lints)]
2+
3+
#![warn(clippy::fn_to_numeric_cast_with_truncation)]
4+
#![allow(clippy::fn_to_numeric_cast)]
5+
6+
fn foo() -> String { String::new() }
7+
8+
fn test_fn_to_numeric_cast_with_truncation() {
9+
let _ = foo as i8;
10+
let _ = foo as i16;
11+
let _ = foo as i32;
12+
let _ = foo as u8;
13+
let _ = foo as u16;
14+
let _ = foo as u32;
15+
16+
// TODO: Is it bad to have these tests?
17+
// Running the tests on a different architechture will
18+
// produce different results
19+
let _ = foo as u64;
20+
let _ = foo as i64;
21+
}
22+
23+
fn main() {}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: casting function pointer `foo` to `i8`, which truncates the value
2+
--> $DIR/fn_to_numeric_cast_with_truncation.rs:9:13
3+
|
4+
9 | let _ = foo as i8;
5+
| ^^^^^^^^^ help: try: `foo as usize`
6+
|
7+
= note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
8+
9+
error: casting function pointer `foo` to `i16`, which truncates the value
10+
--> $DIR/fn_to_numeric_cast_with_truncation.rs:10:13
11+
|
12+
10 | let _ = foo as i16;
13+
| ^^^^^^^^^^ help: try: `foo as usize`
14+
15+
error: casting function pointer `foo` to `i32`, which truncates the value
16+
--> $DIR/fn_to_numeric_cast_with_truncation.rs:11:13
17+
|
18+
11 | let _ = foo as i32;
19+
| ^^^^^^^^^^ help: try: `foo as usize`
20+
21+
error: casting function pointer `foo` to `u8`, which truncates the value
22+
--> $DIR/fn_to_numeric_cast_with_truncation.rs:12:13
23+
|
24+
12 | let _ = foo as u8;
25+
| ^^^^^^^^^ help: try: `foo as usize`
26+
27+
error: casting function pointer `foo` to `u16`, which truncates the value
28+
--> $DIR/fn_to_numeric_cast_with_truncation.rs:13:13
29+
|
30+
13 | let _ = foo as u16;
31+
| ^^^^^^^^^^ help: try: `foo as usize`
32+
33+
error: casting function pointer `foo` to `u32`, which truncates the value
34+
--> $DIR/fn_to_numeric_cast_with_truncation.rs:14:13
35+
|
36+
14 | let _ = foo as u32;
37+
| ^^^^^^^^^^ help: try: `foo as usize`
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)