Auto merge of #10193 - Jarcho:issue_9894, r=Manishearth

Fix suggestion in `transmutes_expressible_as_ptr_casts` when the source type is a borrow.

fixes #9894

changelog: `transmutes_expressible_as_ptr_casts`: Fix suggestion when the source type is a borrow.
This commit is contained in:
bors 2023-01-17 14:58:39 +00:00
commit 89d443a4c3
6 changed files with 60 additions and 43 deletions

View file

@ -479,7 +479,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
// - char conversions (https://github.com/rust-lang/rust/issues/89259)
let const_context = in_constant(cx, e.hir_id);
let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
[] => (cx.typeck_results().expr_ty(arg), false),
[.., a] => (a.target, true),
};
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
let to_ty = cx.typeck_results().expr_ty(e);
@ -506,7 +509,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
);
if !linted {
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
}
}
}

View file

@ -1,11 +1,11 @@
use super::utils::can_be_expressed_as_pointer_cast;
use super::utils::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_middle::ty::{cast::CastKind, Ty};
/// Checks for `transmutes_expressible_as_ptr_casts` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
@ -13,24 +13,40 @@ pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
from_ty_adjusted: bool,
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
) -> bool {
if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
span_lint_and_then(
cx,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
e.span,
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
let sugg = arg.as_ty(to_ty.to_string()).to_string();
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},
);
true
} else {
false
}
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
let mut app = Applicability::MachineApplicable;
let sugg = match check_cast(cx, e, from_ty, to_ty) {
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
.as_ty(to_ty.to_string())
.to_string()
},
Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
.as_ty(to_ty.to_string())
.to_string(),
// The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't
// be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to
// a usize.
Some(PtrAddrCast) => format!(
"{} as {to_ty}",
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty)
),
_ => return false,
};
span_lint_and_sugg(
cx,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
e.span,
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
"try",
sugg,
app,
);
true
}

View file

@ -20,28 +20,16 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
}
}
/// Check if the type conversion can be expressed as a pointer cast, instead of
/// a transmute. In certain cases, including some invalid casts from array
/// references to pointers, this may cause additional errors to be emitted and/or
/// ICE error messages. This function will panic if that occurs.
pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
) -> bool {
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
matches!(
check_cast(cx, e, from_ty, to_ty),
Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
)
}
/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
/// the cast. In certain cases, including some invalid casts from array references
/// to pointers, this may cause additional errors to be emitted and/or ICE error
/// messages. This function will panic if that occurs.
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
pub(super) fn check_cast<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
) -> Option<CastKind> {
let hir_id = e.hir_id;
let local_def_id = hir_id.owner.def_id;

View file

@ -51,6 +51,8 @@ fn main() {
// e is a function pointer type and U is an integer; fptr-addr-cast
let _usize_from_fn_ptr_transmute = unsafe { foo as usize };
let _usize_from_fn_ptr = foo as *const usize;
let _usize_from_ref = unsafe { &1u32 as *const u32 as usize };
}
// If a ref-to-ptr cast of this form where the pointer type points to a type other

View file

@ -51,6 +51,8 @@ fn main() {
// e is a function pointer type and U is an integer; fptr-addr-cast
let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
let _usize_from_fn_ptr = foo as *const usize;
let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
}
// If a ref-to-ptr cast of this form where the pointer type points to a type other

View file

@ -46,11 +46,17 @@ error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a
LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead
--> $DIR/transmutes_expressible_as_ptr_casts.rs:55:36
|
LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize`
error: transmute from a reference to a pointer
--> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14
--> $DIR/transmutes_expressible_as_ptr_casts.rs:66:14
|
LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
error: aborting due to 8 previous errors
error: aborting due to 9 previous errors