use rustc::lint::*;
+use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
+use rustc::ty;
use rustc_front::hir::*;
-use rustc::ty::TyS;
-use rustc::ty::TypeVariants::TyRawPtr;
-use utils;
use utils::TRANSMUTE_PATH;
+use utils::{match_def_path, snippet_opt, span_lint, span_lint_and_then};
/// **What it does:** This lint checks for transmutes to the original type of the object.
///
"transmutes that have to or from types that are a pointer to the other"
}
-pub struct UselessTransmute;
+/// **What it does:*** This lint checks for transmutes from a pointer to a reference.
+///
+/// **Why is this bad?** This can always be rewritten with `&` and `*`.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+/// ```rust
+/// let _: &T = std::mem::transmute(p); // where p: *const T
+/// // can be written:
+/// let _: &T = &*p;
+/// ```
+declare_lint! {
+ pub TRANSMUTE_PTR_TO_REF,
+ Warn,
+ "transmutes from a pointer to a reference type"
+}
+
+pub struct Transmute;
-impl LintPass for UselessTransmute {
+impl LintPass for Transmute {
fn get_lints(&self) -> LintArray {
- lint_array!(USELESS_TRANSMUTE)
+ lint_array! [
+ CROSSPOINTER_TRANSMUTE,
+ TRANSMUTE_PTR_TO_REF,
+ USELESS_TRANSMUTE
+ ]
}
}
-impl LateLintPass for UselessTransmute {
+impl LateLintPass for Transmute {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
if let ExprCall(ref path_expr, ref args) = e.node {
if let ExprPath(None, _) = path_expr.node {
let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id();
- if utils::match_def_path(cx, def_id, &TRANSMUTE_PATH) {
+ if match_def_path(cx, def_id, &TRANSMUTE_PATH) {
let from_ty = cx.tcx.expr_ty(&args[0]);
let to_ty = cx.tcx.expr_ty(e);
if from_ty == to_ty {
- cx.span_lint(USELESS_TRANSMUTE,
- e.span,
- &format!("transmute from a type (`{}`) to itself", from_ty));
+ span_lint(cx,
+ USELESS_TRANSMUTE,
+ e.span,
+ &format!("transmute from a type (`{}`) to itself", from_ty));
+ } else if is_ptr_to(to_ty, from_ty) {
+ span_lint(cx,
+ CROSSPOINTER_TRANSMUTE,
+ e.span,
+ &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty));
+ } else if is_ptr_to(from_ty, to_ty) {
+ span_lint(cx,
+ CROSSPOINTER_TRANSMUTE,
+ e.span,
+ &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", from_ty, to_ty));
+ } else {
+ check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]);
}
}
}
}
}
-pub struct CrosspointerTransmute;
-
-impl LintPass for CrosspointerTransmute {
- fn get_lints(&self) -> LintArray {
- lint_array!(CROSSPOINTER_TRANSMUTE)
- }
-}
-
-fn is_ptr_to(from: &TyS, to: &TyS) -> bool {
+fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool {
if let TyRawPtr(from_ptr) = from.sty {
from_ptr.ty == to
} else {
}
}
-impl LateLintPass for CrosspointerTransmute {
- fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
- if let ExprCall(ref path_expr, ref args) = e.node {
- if let ExprPath(None, _) = path_expr.node {
- let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id();
+fn check_ptr_to_ref<'tcx>(cx: &LateContext,
+ from_ty: ty::Ty<'tcx>,
+ to_ty: ty::Ty<'tcx>,
+ e: &Expr, arg: &Expr) {
+ if let TyRawPtr(ref from_pty) = from_ty.sty {
+ if let TyRef(_, ref to_rty) = to_ty.sty {
+ let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)",
+ from_ty,
+ to_ty);
+ span_lint_and_then(cx, TRANSMUTE_PTR_TO_REF, e.span, &mess, |db| {
+ if let Some(arg) = snippet_opt(cx, arg.span) {
+ let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable {
+ ("&mut *", "*mut")
+ } else {
+ ("&*", "*const")
+ };
- if utils::match_def_path(cx, def_id, &TRANSMUTE_PATH) {
- let from_ty = cx.tcx.expr_ty(&args[0]);
- let to_ty = cx.tcx.expr_ty(e);
- if is_ptr_to(to_ty, from_ty) {
- cx.span_lint(CROSSPOINTER_TRANSMUTE,
- e.span,
- &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty));
- } else if is_ptr_to(from_ty, to_ty) {
- cx.span_lint(CROSSPOINTER_TRANSMUTE,
- e.span,
- &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", from_ty, to_ty));
+ let sugg = if from_pty.ty == to_rty.ty {
+ format!("{}{}", deref, arg)
}
+ else {
+ format!("{}({} as {} {})", deref, arg, cast, to_rty.ty)
+ };
+
+ db.span_suggestion(e.span, "try", sugg);
}
- }
+ });
}
}
}
let _: &'a U = core::intrinsics::transmute(t);
}
+#[deny(transmute_ptr_to_ref)]
+unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
+ let _: &T = std::mem::transmute(p);
+ //~^ ERROR transmute from a pointer type (`*const T`) to a reference type (`&T`)
+ //~| HELP try
+ //~| SUGGESTION = &*p;
+ let _: &T = &*p;
+
+ let _: &mut T = std::mem::transmute(m);
+ //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
+ //~| HELP try
+ //~| SUGGESTION = &mut *m;
+ let _: &mut T = &mut *m;
+
+ let _: &T = std::mem::transmute(m);
+ //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&T`)
+ //~| HELP try
+ //~| SUGGESTION = &*m;
+ let _: &T = &*m;
+
+ let _: &T = std::mem::transmute(o);
+ //~^ ERROR transmute from a pointer type (`*const U`) to a reference type (`&T`)
+ //~| HELP try
+ //~| SUGGESTION = &*(o as *const T);
+ let _: &T = &*(o as *const T);
+
+ let _: &mut T = std::mem::transmute(om);
+ //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
+ //~| HELP try
+ //~| SUGGESTION = &mut *(om as *mut T);
+ let _: &mut T = &mut *(om as *mut T);
+
+ let _: &T = std::mem::transmute(om);
+ //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&T`)
+ //~| HELP try
+ //~| SUGGESTION = &*(om as *const T);
+ let _: &T = &*(om as *const T);
+}
+
#[deny(useless_transmute)]
fn useless() {
unsafe {