Merge pull request #1053 from oli-obk/char_float_transmute

lint on unnecessary and plain wrong transmutes
This commit is contained in:
Oliver Schneider 2016-06-28 14:50:39 +02:00 committed by GitHub
commit 9ceb708727
7 changed files with 102 additions and 19 deletions

View file

@ -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
<!-- end autogenerated links to wiki -->

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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<i32> {
@ -105,27 +105,34 @@ fn useless() {
let _: Vec<u32> = std::intrinsics::transmute(my_vec());
let _: Vec<u32> = std::mem::transmute(my_vec());
let _: Vec<u32> = 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`)
}
}

View file

@ -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
}
}

View file

@ -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
}
}