Skip to content

Commit 8a505c2

Browse files
oli-obkmcarton
authored andcommitted
lint on unnecessary and plain wrong transmutes
1 parent ddc1b7c commit 8a505c2

File tree

7 files changed

+102
-19
lines changed

7 files changed

+102
-19
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Change Log
22
All notable changes to this project will be documented in this file.
33

4+
## 0.0.78 - TBA
5+
* New lints: [`wrong_transmute`]
6+
47
## 0.0.77 — 2016-06-21
58
* Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
69
* New lints: [`stutter`] and [`iter_nth`]
@@ -276,6 +279,7 @@ All notable changes to this project will be documented in this file.
276279
[`while_let_on_iterator`]: https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator
277280
[`wrong_pub_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention
278281
[`wrong_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention
282+
[`wrong_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute
279283
[`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero
280284
[`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space
281285
<!-- end autogenerated links to wiki -->

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Table of contents:
1717

1818
## Lints
1919

20-
There are 155 lints included in this crate:
20+
There are 156 lints included in this crate:
2121

2222
name | default | meaning
2323
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -168,12 +168,13 @@ name
168168
[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | allow | using a binding which is prefixed with an underscore
169169
[useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!`
170170
[useless_let_if_seq](https://github.com/Manishearth/rust-clippy/wiki#useless_let_if_seq) | warn | Checks for unidiomatic `let mut` declaration followed by initialization in `if`
171-
[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types
171+
[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types or could be a cast/coercion
172172
[useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!`
173173
[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop
174174
[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator
175175
[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention
176176
[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention
177+
[wrong_transmute](https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute) | warn | transmutes that are confusing at best, undefined behaviour at worst and always useless
177178
[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN
178179
[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing
179180

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
403403
transmute::CROSSPOINTER_TRANSMUTE,
404404
transmute::TRANSMUTE_PTR_TO_REF,
405405
transmute::USELESS_TRANSMUTE,
406+
transmute::WRONG_TRANSMUTE,
406407
types::ABSURD_EXTREME_COMPARISONS,
407408
types::BOX_VEC,
408409
types::CHAR_LIT_AS_U8,

clippy_lints/src/transmute.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
use rustc::lint::*;
22
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
3+
use rustc::ty;
34
use rustc::hir::*;
45
use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then};
56

6-
/// **What it does:** This lint checks for transmutes to the original type of the object.
7+
/// **What it does:** This lint checks for transmutes that can't ever be correct on any architecture
78
///
8-
/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type.
9+
/// **Why is this bad?** It's basically guaranteed to be undefined behaviour
10+
///
11+
/// **Known problems:** When accessing C, users might want to store pointer sized objects in `extradata` arguments to save an allocation.
12+
///
13+
/// **Example:** `let ptr: *const T = core::intrinsics::transmute('x')`.
14+
declare_lint! {
15+
pub WRONG_TRANSMUTE,
16+
Warn,
17+
"transmutes that are confusing at best, undefined behaviour at worst and always useless"
18+
}
19+
20+
/// **What it does:** This lint checks for transmutes to the original type of the object and transmutes that could be a cast.
21+
///
22+
/// **Why is this bad?** Readability. The code tricks people into thinking that something complex is going on
923
///
1024
/// **Known problems:** None.
1125
///
1226
/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `t`'s.
1327
declare_lint! {
1428
pub USELESS_TRANSMUTE,
1529
Warn,
16-
"transmutes that have the same to and from types"
30+
"transmutes that have the same to and from types or could be a cast/coercion"
1731
}
1832

1933
/// **What it does:*** This lint checks for transmutes between a type `T` and `*T`.
@@ -51,7 +65,7 @@ pub struct Transmute;
5165

5266
impl LintPass for Transmute {
5367
fn get_lints(&self) -> LintArray {
54-
lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE]
68+
lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE]
5569
}
5670
}
5771

@@ -89,6 +103,27 @@ impl LateLintPass for Transmute {
89103
}
90104
},
91105
),
106+
(&ty::TyInt(_), &TyRawPtr(_)) |
107+
(&ty::TyUint(_), &TyRawPtr(_)) => span_lint_and_then(
108+
cx,
109+
USELESS_TRANSMUTE,
110+
e.span,
111+
"transmute from an integer to a pointer",
112+
|db| {
113+
if let Some(arg) = snippet_opt(cx, args[0].span) {
114+
db.span_suggestion(e.span, "try", format!("{} as {}", arg, to_ty));
115+
}
116+
},
117+
),
118+
(&ty::TyFloat(_), &TyRef(..)) |
119+
(&ty::TyFloat(_), &TyRawPtr(_)) |
120+
(&ty::TyChar, &TyRef(..)) |
121+
(&ty::TyChar, &TyRawPtr(_)) => span_lint(
122+
cx,
123+
WRONG_TRANSMUTE,
124+
e.span,
125+
&format!("transmute from a `{}` to a pointer", from_ty),
126+
),
92127
(&TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
93128
cx,
94129
CROSSPOINTER_TRANSMUTE,

tests/compile-fail/transmute.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ extern crate core;
66
use std::mem::transmute as my_transmute;
77
use std::vec::Vec as MyVec;
88

9-
fn my_int() -> usize {
10-
42
9+
fn my_int() -> Usize {
10+
Usize(42)
1111
}
1212

1313
fn my_vec() -> MyVec<i32> {
@@ -105,27 +105,34 @@ fn useless() {
105105
let _: Vec<u32> = std::intrinsics::transmute(my_vec());
106106
let _: Vec<u32> = std::mem::transmute(my_vec());
107107
let _: Vec<u32> = my_transmute(my_vec());
108+
109+
let _: *const usize = std::mem::transmute(5_isize);
110+
//~^ ERROR transmute from an integer to a pointer
111+
//~| HELP try
112+
//~| SUGGESTION 5_isize as *const usize
108113
}
109114
}
110115

116+
struct Usize(usize);
117+
111118
#[deny(crosspointer_transmute)]
112119
fn crosspointer() {
113-
let mut int: usize = 0;
114-
let int_const_ptr: *const usize = &int as *const usize;
115-
let int_mut_ptr: *mut usize = &mut int as *mut usize;
120+
let mut int: Usize = Usize(0);
121+
let int_const_ptr: *const Usize = &int as *const Usize;
122+
let int_mut_ptr: *mut Usize = &mut int as *mut Usize;
116123

117124
unsafe {
118-
let _: usize = core::intrinsics::transmute(int_const_ptr);
119-
//~^ ERROR transmute from a type (`*const usize`) to the type that it points to (`usize`)
125+
let _: Usize = core::intrinsics::transmute(int_const_ptr);
126+
//~^ ERROR transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
120127

121-
let _: usize = core::intrinsics::transmute(int_mut_ptr);
122-
//~^ ERROR transmute from a type (`*mut usize`) to the type that it points to (`usize`)
128+
let _: Usize = core::intrinsics::transmute(int_mut_ptr);
129+
//~^ ERROR transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
123130

124-
let _: *const usize = core::intrinsics::transmute(my_int());
125-
//~^ ERROR transmute from a type (`usize`) to a pointer to that type (`*const usize`)
131+
let _: *const Usize = core::intrinsics::transmute(my_int());
132+
//~^ ERROR transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
126133

127-
let _: *mut usize = core::intrinsics::transmute(my_int());
128-
//~^ ERROR transmute from a type (`usize`) to a pointer to that type (`*mut usize`)
134+
let _: *mut Usize = core::intrinsics::transmute(my_int());
135+
//~^ ERROR transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
129136
}
130137
}
131138

tests/compile-fail/transmute_32bit.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//ignore-x86_64
2+
#![feature(plugin)]
3+
#![plugin(clippy)]
4+
5+
#[deny(wrong_transmute)]
6+
fn main() {
7+
unsafe {
8+
let _: *const usize = std::mem::transmute(6.0f32);
9+
//~^ ERROR transmute from a `f32` to a pointer
10+
11+
let _: *mut usize = std::mem::transmute(6.0f32);
12+
//~^ ERROR transmute from a `f32` to a pointer
13+
14+
let _: *const usize = std::mem::transmute('x');
15+
//~^ ERROR transmute from a `char` to a pointer
16+
17+
let _: *mut usize = std::mem::transmute('x');
18+
//~^ ERROR transmute from a `char` to a pointer
19+
}
20+
}

tests/compile-fail/transmute_64bit.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//ignore-x86
2+
//no-ignore-x86_64
3+
#![feature(plugin)]
4+
#![plugin(clippy)]
5+
6+
#[deny(wrong_transmute)]
7+
fn main() {
8+
unsafe {
9+
let _: *const usize = std::mem::transmute(6.0f64);
10+
//~^ ERROR transmute from a `f64` to a pointer
11+
12+
let _: *mut usize = std::mem::transmute(6.0f64);
13+
//~^ ERROR transmute from a `f64` to a pointer
14+
}
15+
}

0 commit comments

Comments
 (0)