Skip to content

Commit afe811a

Browse files
committed
Suggest .cast/.cast_const/.cast_mut in transmute_ptr_as_ptr
1 parent 1807580 commit afe811a

7 files changed

+274
-80
lines changed

clippy_lints/src/transmute/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
617617
| missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
618618
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
619619
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
620-
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
620+
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv)
621621
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
622622
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
623623
| transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)

clippy_lints/src/transmute/transmute_ptr_to_ptr.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::TRANSMUTE_PTR_TO_PTR;
2+
use clippy_config::msrvs::{self, Msrv};
23
use clippy_utils::diagnostics::span_lint_and_then;
34
use clippy_utils::sugg;
45
use rustc_errors::Applicability;
@@ -14,18 +15,49 @@ pub(super) fn check<'tcx>(
1415
from_ty: Ty<'tcx>,
1516
to_ty: Ty<'tcx>,
1617
arg: &'tcx Expr<'_>,
18+
msrv: &Msrv,
1719
) -> bool {
18-
match (&from_ty.kind(), &to_ty.kind()) {
19-
(ty::RawPtr(_, _), ty::RawPtr(to_ty, to_mutbl)) => {
20+
match (from_ty.kind(), to_ty.kind()) {
21+
(ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => {
2022
span_lint_and_then(
2123
cx,
2224
TRANSMUTE_PTR_TO_PTR,
2325
e.span,
2426
"transmute from a pointer to a pointer",
2527
|diag| {
2628
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
27-
let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty, *to_mutbl));
28-
diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
29+
if from_mutbl == to_mutbl
30+
&& to_pointee_ty.is_sized(cx.tcx, cx.param_env)
31+
&& msrv.meets(msrvs::POINTER_CAST)
32+
{
33+
diag.span_suggestion_verbose(
34+
e.span,
35+
"use `pointer::cast` instead",
36+
format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_par()),
37+
Applicability::MaybeIncorrect,
38+
);
39+
} else if from_pointee_ty == to_pointee_ty
40+
&& let Some(method) = match (from_mutbl, to_mutbl) {
41+
(ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"),
42+
(ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"),
43+
_ => None,
44+
}
45+
&& msrv.meets(msrvs::POINTER_CAST_CONSTNESS)
46+
{
47+
diag.span_suggestion_verbose(
48+
e.span,
49+
format!("use `pointer::{method}` instead"),
50+
format!("{}.{method}()", arg.maybe_par()),
51+
Applicability::MaybeIncorrect,
52+
);
53+
} else {
54+
diag.span_suggestion_verbose(
55+
e.span,
56+
"use an `as` cast instead",
57+
arg.as_ty(to_ty),
58+
Applicability::MaybeIncorrect,
59+
);
60+
}
2961
}
3062
},
3163
);

tests/ui/transmute_ptr_to_ptr.fixed

+51-23
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
#![warn(clippy::transmute_ptr_to_ptr)]
22
#![allow(clippy::borrow_as_ptr, clippy::missing_transmute_annotations)]
33

4+
use std::mem::transmute;
5+
46
// Make sure we can modify lifetimes, which is one of the recommended uses
57
// of transmute
68

79
// Make sure we can do static lifetime transmutes
810
unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
9-
std::mem::transmute::<&'a T, &'static T>(t)
11+
transmute::<&'a T, &'static T>(t)
1012
}
1113

1214
// Make sure we can do non-static lifetime transmutes
1315
unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
14-
std::mem::transmute::<&'a T, &'b T>(t)
16+
transmute::<&'a T, &'b T>(t)
1517
}
1618

1719
struct LifetimeParam<'a> {
@@ -27,47 +29,73 @@ fn transmute_ptr_to_ptr() {
2729
let mut_ptr = &mut 1u32 as *mut u32;
2830
unsafe {
2931
// pointer-to-pointer transmutes; bad
30-
let _: *const f32 = ptr as *const f32;
31-
//~^ ERROR: transmute from a pointer to a pointer
32-
//~| NOTE: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
33-
let _: *mut f32 = mut_ptr as *mut f32;
34-
//~^ ERROR: transmute from a pointer to a pointer
32+
let _: *const f32 = ptr.cast::<f32>();
33+
//~^ transmute_ptr_to_ptr
34+
let _: *mut f32 = mut_ptr.cast::<f32>();
35+
//~^ transmute_ptr_to_ptr
3536
// ref-ref transmutes; bad
3637
let _: &f32 = &*(&1u32 as *const u32 as *const f32);
37-
//~^ ERROR: transmute from a reference to a reference
38+
//~^ transmute_ptr_to_ptr
3839
let _: &f32 = &*(&1f64 as *const f64 as *const f32);
39-
//~^ ERROR: transmute from a reference to a reference
40+
//~^ transmute_ptr_to_ptr
4041
//:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not
4142
// the same type
4243
let _: &mut f32 = &mut *(&mut 1u32 as *mut u32 as *mut f32);
43-
//~^ ERROR: transmute from a reference to a reference
44+
//~^ transmute_ptr_to_ptr
4445
let _: &GenericParam<f32> = &*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>);
45-
//~^ ERROR: transmute from a reference to a reference
46+
//~^ transmute_ptr_to_ptr
4647
let u64_ref: &u64 = &0u64;
47-
let u8_ref: &u8 = unsafe { &*(u64_ref as *const u64 as *const u8) };
48-
//~^ ERROR: transmute from a reference to a reference
48+
let u8_ref: &u8 = &*(u64_ref as *const u64 as *const u8);
49+
//~^ transmute_ptr_to_ptr
50+
let _: *const u32 = mut_ptr.cast_const();
51+
//~^ transmute_ptr_to_ptr
52+
let _: *mut u32 = ptr.cast_mut();
53+
//~^ transmute_ptr_to_ptr
4954
}
5055

51-
// these are recommendations for solving the above; if these lint we need to update
52-
// those suggestions
53-
let _ = ptr as *const f32;
54-
let _ = mut_ptr as *mut f32;
55-
let _ = unsafe { &*(&1u32 as *const u32 as *const f32) };
56-
let _ = unsafe { &mut *(&mut 1u32 as *mut u32 as *mut f32) };
57-
5856
// transmute internal lifetimes, should not lint
5957
let s = "hello world".to_owned();
6058
let lp = LifetimeParam { s: &s };
61-
let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) };
62-
let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) };
59+
let _: &LifetimeParam<'static> = unsafe { transmute(&lp) };
60+
let _: &GenericParam<&LifetimeParam<'static>> = unsafe { transmute(&GenericParam { t: &lp }) };
6361
}
6462

6563
// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959)
6664
const _: &() = {
6765
struct Zst;
6866
let zst = &Zst;
6967

70-
unsafe { std::mem::transmute::<&'static Zst, &'static ()>(zst) }
68+
unsafe { transmute::<&'static Zst, &'static ()>(zst) }
7169
};
7270

71+
#[clippy::msrv = "1.37"]
72+
fn msrv_1_37(ptr: *const u8) {
73+
unsafe {
74+
let _: *const i8 = ptr as *const i8;
75+
}
76+
}
77+
78+
#[clippy::msrv = "1.38"]
79+
fn msrv_1_38(ptr: *const u8) {
80+
unsafe {
81+
let _: *const i8 = ptr.cast::<i8>();
82+
}
83+
}
84+
85+
#[clippy::msrv = "1.64"]
86+
fn msrv_1_64(ptr: *const u8, mut_ptr: *mut u8) {
87+
unsafe {
88+
let _: *mut u8 = ptr as *mut u8;
89+
let _: *const u8 = mut_ptr as *const u8;
90+
}
91+
}
92+
93+
#[clippy::msrv = "1.65"]
94+
fn msrv_1_65(ptr: *const u8, mut_ptr: *mut u8) {
95+
unsafe {
96+
let _: *mut u8 = ptr.cast_mut();
97+
let _: *const u8 = mut_ptr.cast_const();
98+
}
99+
}
100+
73101
fn main() {}

tests/ui/transmute_ptr_to_ptr.rs

+55-27
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
#![warn(clippy::transmute_ptr_to_ptr)]
22
#![allow(clippy::borrow_as_ptr, clippy::missing_transmute_annotations)]
33

4+
use std::mem::transmute;
5+
46
// Make sure we can modify lifetimes, which is one of the recommended uses
57
// of transmute
68

79
// Make sure we can do static lifetime transmutes
810
unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
9-
std::mem::transmute::<&'a T, &'static T>(t)
11+
transmute::<&'a T, &'static T>(t)
1012
}
1113

1214
// Make sure we can do non-static lifetime transmutes
1315
unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
14-
std::mem::transmute::<&'a T, &'b T>(t)
16+
transmute::<&'a T, &'b T>(t)
1517
}
1618

1719
struct LifetimeParam<'a> {
@@ -27,47 +29,73 @@ fn transmute_ptr_to_ptr() {
2729
let mut_ptr = &mut 1u32 as *mut u32;
2830
unsafe {
2931
// pointer-to-pointer transmutes; bad
30-
let _: *const f32 = std::mem::transmute(ptr);
31-
//~^ ERROR: transmute from a pointer to a pointer
32-
//~| NOTE: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
33-
let _: *mut f32 = std::mem::transmute(mut_ptr);
34-
//~^ ERROR: transmute from a pointer to a pointer
32+
let _: *const f32 = transmute(ptr);
33+
//~^ transmute_ptr_to_ptr
34+
let _: *mut f32 = transmute(mut_ptr);
35+
//~^ transmute_ptr_to_ptr
3536
// ref-ref transmutes; bad
36-
let _: &f32 = std::mem::transmute(&1u32);
37-
//~^ ERROR: transmute from a reference to a reference
38-
let _: &f32 = std::mem::transmute(&1f64);
39-
//~^ ERROR: transmute from a reference to a reference
37+
let _: &f32 = transmute(&1u32);
38+
//~^ transmute_ptr_to_ptr
39+
let _: &f32 = transmute(&1f64);
40+
//~^ transmute_ptr_to_ptr
4041
//:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not
4142
// the same type
42-
let _: &mut f32 = std::mem::transmute(&mut 1u32);
43-
//~^ ERROR: transmute from a reference to a reference
44-
let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
45-
//~^ ERROR: transmute from a reference to a reference
43+
let _: &mut f32 = transmute(&mut 1u32);
44+
//~^ transmute_ptr_to_ptr
45+
let _: &GenericParam<f32> = transmute(&GenericParam { t: 1u32 });
46+
//~^ transmute_ptr_to_ptr
4647
let u64_ref: &u64 = &0u64;
47-
let u8_ref: &u8 = unsafe { std::mem::transmute(u64_ref) };
48-
//~^ ERROR: transmute from a reference to a reference
48+
let u8_ref: &u8 = transmute(u64_ref);
49+
//~^ transmute_ptr_to_ptr
50+
let _: *const u32 = transmute(mut_ptr);
51+
//~^ transmute_ptr_to_ptr
52+
let _: *mut u32 = transmute(ptr);
53+
//~^ transmute_ptr_to_ptr
4954
}
5055

51-
// these are recommendations for solving the above; if these lint we need to update
52-
// those suggestions
53-
let _ = ptr as *const f32;
54-
let _ = mut_ptr as *mut f32;
55-
let _ = unsafe { &*(&1u32 as *const u32 as *const f32) };
56-
let _ = unsafe { &mut *(&mut 1u32 as *mut u32 as *mut f32) };
57-
5856
// transmute internal lifetimes, should not lint
5957
let s = "hello world".to_owned();
6058
let lp = LifetimeParam { s: &s };
61-
let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) };
62-
let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) };
59+
let _: &LifetimeParam<'static> = unsafe { transmute(&lp) };
60+
let _: &GenericParam<&LifetimeParam<'static>> = unsafe { transmute(&GenericParam { t: &lp }) };
6361
}
6462

6563
// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959)
6664
const _: &() = {
6765
struct Zst;
6866
let zst = &Zst;
6967

70-
unsafe { std::mem::transmute::<&'static Zst, &'static ()>(zst) }
68+
unsafe { transmute::<&'static Zst, &'static ()>(zst) }
7169
};
7270

71+
#[clippy::msrv = "1.37"]
72+
fn msrv_1_37(ptr: *const u8) {
73+
unsafe {
74+
let _: *const i8 = transmute(ptr);
75+
}
76+
}
77+
78+
#[clippy::msrv = "1.38"]
79+
fn msrv_1_38(ptr: *const u8) {
80+
unsafe {
81+
let _: *const i8 = transmute(ptr);
82+
}
83+
}
84+
85+
#[clippy::msrv = "1.64"]
86+
fn msrv_1_64(ptr: *const u8, mut_ptr: *mut u8) {
87+
unsafe {
88+
let _: *mut u8 = transmute(ptr);
89+
let _: *const u8 = transmute(mut_ptr);
90+
}
91+
}
92+
93+
#[clippy::msrv = "1.65"]
94+
fn msrv_1_65(ptr: *const u8, mut_ptr: *mut u8) {
95+
unsafe {
96+
let _: *mut u8 = transmute(ptr);
97+
let _: *const u8 = transmute(mut_ptr);
98+
}
99+
}
100+
73101
fn main() {}

0 commit comments

Comments
 (0)