diff --git a/CHANGELOG.md b/CHANGELOG.md index 728ed347da2..a71b410a5f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.78 - TBA +* New lints: [`wrong_transmute`] + ## 0.0.77 — 2016-06-21 * Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)* * New lints: [`stutter`] and [`iter_nth`] @@ -276,6 +279,7 @@ All notable changes to this project will be documented in this file. [`while_let_on_iterator`]: https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator [`wrong_pub_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention [`wrong_self_convention`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention +[`wrong_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#wrong_transmute [`zero_divided_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero [`zero_width_space`]: https://github.com/Manishearth/rust-clippy/wiki#zero_width_space diff --git a/README.md b/README.md index c01fac4d5f9..5096ee953b2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 155 lints included in this crate: +There are 156 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -168,12 +168,13 @@ name [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | allow | using a binding which is prefixed with an underscore [useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!` [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` -[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types +[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 [useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` [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 [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 [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 [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 +[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 [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 [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 diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 835823b8cd3..3fd94661f67 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -403,6 +403,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { transmute::CROSSPOINTER_TRANSMUTE, transmute::TRANSMUTE_PTR_TO_REF, transmute::USELESS_TRANSMUTE, + transmute::WRONG_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, types::BOX_VEC, types::CHAR_LIT_AS_U8, diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 074e4bffec1..bf6af4411b8 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,11 +1,25 @@ use rustc::lint::*; use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; +use rustc::ty; use rustc::hir::*; use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then}; -/// **What it does:** This lint checks for transmutes to the original type of the object. +/// **What it does:** This lint checks for transmutes that can't ever be correct on any architecture /// -/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type. +/// **Why is this bad?** It's basically guaranteed to be undefined behaviour +/// +/// **Known problems:** When accessing C, users might want to store pointer sized objects in `extradata` arguments to save an allocation. +/// +/// **Example:** `let ptr: *const T = core::intrinsics::transmute('x')`. +declare_lint! { + pub WRONG_TRANSMUTE, + Warn, + "transmutes that are confusing at best, undefined behaviour at worst and always useless" +} + +/// **What it does:** This lint checks for transmutes to the original type of the object and transmutes that could be a cast. +/// +/// **Why is this bad?** Readability. The code tricks people into thinking that something complex is going on /// /// **Known problems:** None. /// @@ -13,7 +27,7 @@ use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then}; declare_lint! { pub USELESS_TRANSMUTE, Warn, - "transmutes that have the same to and from types" + "transmutes that have the same to and from types or could be a cast/coercion" } /// **What it does:*** This lint checks for transmutes between a type `T` and `*T`. @@ -51,7 +65,7 @@ pub struct Transmute; impl LintPass for Transmute { fn get_lints(&self) -> LintArray { - lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE] + lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE] } } @@ -89,6 +103,27 @@ impl LateLintPass for Transmute { } }, ), + (&ty::TyInt(_), &TyRawPtr(_)) | + (&ty::TyUint(_), &TyRawPtr(_)) => span_lint_and_then( + cx, + USELESS_TRANSMUTE, + e.span, + "transmute from an integer to a pointer", + |db| { + if let Some(arg) = snippet_opt(cx, args[0].span) { + db.span_suggestion(e.span, "try", format!("{} as {}", arg, to_ty)); + } + }, + ), + (&ty::TyFloat(_), &TyRef(..)) | + (&ty::TyFloat(_), &TyRawPtr(_)) | + (&ty::TyChar, &TyRef(..)) | + (&ty::TyChar, &TyRawPtr(_)) => span_lint( + cx, + WRONG_TRANSMUTE, + e.span, + &format!("transmute from a `{}` to a pointer", from_ty), + ), (&TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint( cx, CROSSPOINTER_TRANSMUTE, diff --git a/tests/compile-fail/transmute.rs b/tests/compile-fail/transmute.rs index a0f7ba0ccde..4a120a6eedd 100644 --- a/tests/compile-fail/transmute.rs +++ b/tests/compile-fail/transmute.rs @@ -6,8 +6,8 @@ extern crate core; use std::mem::transmute as my_transmute; use std::vec::Vec as MyVec; -fn my_int() -> usize { - 42 +fn my_int() -> Usize { + Usize(42) } fn my_vec() -> MyVec { @@ -105,27 +105,34 @@ fn useless() { let _: Vec = std::intrinsics::transmute(my_vec()); let _: Vec = std::mem::transmute(my_vec()); let _: Vec = my_transmute(my_vec()); + + let _: *const usize = std::mem::transmute(5_isize); + //~^ ERROR transmute from an integer to a pointer + //~| HELP try + //~| SUGGESTION 5_isize as *const usize } } +struct Usize(usize); + #[deny(crosspointer_transmute)] fn crosspointer() { - let mut int: usize = 0; - let int_const_ptr: *const usize = &int as *const usize; - let int_mut_ptr: *mut usize = &mut int as *mut usize; + let mut int: Usize = Usize(0); + let int_const_ptr: *const Usize = &int as *const Usize; + let int_mut_ptr: *mut Usize = &mut int as *mut Usize; unsafe { - let _: usize = core::intrinsics::transmute(int_const_ptr); - //~^ ERROR transmute from a type (`*const usize`) to the type that it points to (`usize`) + let _: Usize = core::intrinsics::transmute(int_const_ptr); + //~^ ERROR transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - let _: usize = core::intrinsics::transmute(int_mut_ptr); - //~^ ERROR transmute from a type (`*mut usize`) to the type that it points to (`usize`) + let _: Usize = core::intrinsics::transmute(int_mut_ptr); + //~^ ERROR transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - let _: *const usize = core::intrinsics::transmute(my_int()); - //~^ ERROR transmute from a type (`usize`) to a pointer to that type (`*const usize`) + let _: *const Usize = core::intrinsics::transmute(my_int()); + //~^ ERROR transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - let _: *mut usize = core::intrinsics::transmute(my_int()); - //~^ ERROR transmute from a type (`usize`) to a pointer to that type (`*mut usize`) + let _: *mut Usize = core::intrinsics::transmute(my_int()); + //~^ ERROR transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) } } diff --git a/tests/compile-fail/transmute_32bit.rs b/tests/compile-fail/transmute_32bit.rs new file mode 100644 index 00000000000..1368ab5015d --- /dev/null +++ b/tests/compile-fail/transmute_32bit.rs @@ -0,0 +1,20 @@ +//ignore-x86_64 +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(wrong_transmute)] +fn main() { + unsafe { + let _: *const usize = std::mem::transmute(6.0f32); + //~^ ERROR transmute from a `f32` to a pointer + + let _: *mut usize = std::mem::transmute(6.0f32); + //~^ ERROR transmute from a `f32` to a pointer + + let _: *const usize = std::mem::transmute('x'); + //~^ ERROR transmute from a `char` to a pointer + + let _: *mut usize = std::mem::transmute('x'); + //~^ ERROR transmute from a `char` to a pointer + } +} diff --git a/tests/compile-fail/transmute_64bit.rs b/tests/compile-fail/transmute_64bit.rs new file mode 100644 index 00000000000..8bc6a2367b9 --- /dev/null +++ b/tests/compile-fail/transmute_64bit.rs @@ -0,0 +1,15 @@ +//ignore-x86 +//no-ignore-x86_64 +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(wrong_transmute)] +fn main() { + unsafe { + let _: *const usize = std::mem::transmute(6.0f64); + //~^ ERROR transmute from a `f64` to a pointer + + let _: *mut usize = std::mem::transmute(6.0f64); + //~^ ERROR transmute from a `f64` to a pointer + } +}