Skip to content

Commit b38848d

Browse files
committed
Fix suggestion in transmutes_expressible_as_ptr_casts when the source type is a borrow.
1 parent 0b8ee70 commit b38848d

6 files changed

+60
-43
lines changed

clippy_lints/src/transmute/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
479479
// - char conversions (https://github.com/rust-lang/rust/issues/89259)
480480
let const_context = in_constant(cx, e.hir_id);
481481

482-
let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
482+
let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
483+
[] => (cx.typeck_results().expr_ty(arg), false),
484+
[.., a] => (a.target, true),
485+
};
483486
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
484487
let to_ty = cx.typeck_results().expr_ty(e);
485488

@@ -506,7 +509,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
506509
);
507510

508511
if !linted {
509-
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
512+
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
510513
}
511514
}
512515
}
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,52 @@
1-
use super::utils::can_be_expressed_as_pointer_cast;
1+
use super::utils::check_cast;
22
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
3-
use clippy_utils::diagnostics::span_lint_and_then;
4-
use clippy_utils::sugg;
3+
use clippy_utils::diagnostics::span_lint_and_sugg;
4+
use clippy_utils::sugg::Sugg;
55
use rustc_errors::Applicability;
66
use rustc_hir::Expr;
77
use rustc_lint::LateContext;
8-
use rustc_middle::ty::Ty;
8+
use rustc_middle::ty::{cast::CastKind, Ty};
99

1010
/// Checks for `transmutes_expressible_as_ptr_casts` lint.
1111
/// Returns `true` if it's triggered, otherwise returns `false`.
1212
pub(super) fn check<'tcx>(
1313
cx: &LateContext<'tcx>,
1414
e: &'tcx Expr<'_>,
1515
from_ty: Ty<'tcx>,
16+
from_ty_adjusted: bool,
1617
to_ty: Ty<'tcx>,
1718
arg: &'tcx Expr<'_>,
1819
) -> bool {
19-
if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
20-
span_lint_and_then(
21-
cx,
22-
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
23-
e.span,
24-
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
25-
|diag| {
26-
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
27-
let sugg = arg.as_ty(to_ty.to_string()).to_string();
28-
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
29-
}
30-
},
31-
);
32-
true
33-
} else {
34-
false
35-
}
20+
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
21+
let mut app = Applicability::MachineApplicable;
22+
let sugg = match check_cast(cx, e, from_ty, to_ty) {
23+
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
24+
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
25+
.as_ty(to_ty.to_string())
26+
.to_string()
27+
},
28+
Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
29+
.as_ty(to_ty.to_string())
30+
.to_string(),
31+
32+
// The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't
33+
// be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to
34+
// a usize.
35+
Some(PtrAddrCast) => format!(
36+
"{} as {to_ty}",
37+
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty)
38+
),
39+
_ => return false,
40+
};
41+
42+
span_lint_and_sugg(
43+
cx,
44+
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
45+
e.span,
46+
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
47+
"try",
48+
sugg,
49+
app,
50+
);
51+
true
3652
}

clippy_lints/src/transmute/utils.rs

+6-18
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,16 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
2020
}
2121
}
2222

23-
/// Check if the type conversion can be expressed as a pointer cast, instead of
24-
/// a transmute. In certain cases, including some invalid casts from array
25-
/// references to pointers, this may cause additional errors to be emitted and/or
26-
/// ICE error messages. This function will panic if that occurs.
27-
pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
28-
cx: &LateContext<'tcx>,
29-
e: &'tcx Expr<'_>,
30-
from_ty: Ty<'tcx>,
31-
to_ty: Ty<'tcx>,
32-
) -> bool {
33-
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
34-
matches!(
35-
check_cast(cx, e, from_ty, to_ty),
36-
Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
37-
)
38-
}
39-
4023
/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
4124
/// the cast. In certain cases, including some invalid casts from array references
4225
/// to pointers, this may cause additional errors to be emitted and/or ICE error
4326
/// messages. This function will panic if that occurs.
44-
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
27+
pub(super) fn check_cast<'tcx>(
28+
cx: &LateContext<'tcx>,
29+
e: &'tcx Expr<'_>,
30+
from_ty: Ty<'tcx>,
31+
to_ty: Ty<'tcx>,
32+
) -> Option<CastKind> {
4533
let hir_id = e.hir_id;
4634
let local_def_id = hir_id.owner.def_id;
4735

tests/ui/transmutes_expressible_as_ptr_casts.fixed

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ fn main() {
5151
// e is a function pointer type and U is an integer; fptr-addr-cast
5252
let _usize_from_fn_ptr_transmute = unsafe { foo as usize };
5353
let _usize_from_fn_ptr = foo as *const usize;
54+
55+
let _usize_from_ref = unsafe { &1u32 as *const u32 as usize };
5456
}
5557

5658
// If a ref-to-ptr cast of this form where the pointer type points to a type other

tests/ui/transmutes_expressible_as_ptr_casts.rs

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ fn main() {
5151
// e is a function pointer type and U is an integer; fptr-addr-cast
5252
let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
5353
let _usize_from_fn_ptr = foo as *const usize;
54+
55+
let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
5456
}
5557

5658
// If a ref-to-ptr cast of this form where the pointer type points to a type other

tests/ui/transmutes_expressible_as_ptr_casts.stderr

+8-2
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,17 @@ error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a
4646
LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
4848

49+
error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead
50+
--> $DIR/transmutes_expressible_as_ptr_casts.rs:55:36
51+
|
52+
LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize`
54+
4955
error: transmute from a reference to a pointer
50-
--> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14
56+
--> $DIR/transmutes_expressible_as_ptr_casts.rs:66:14
5157
|
5258
LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
5359
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
5460

55-
error: aborting due to 8 previous errors
61+
error: aborting due to 9 previous errors
5662

0 commit comments

Comments
 (0)