Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions clippy_lints/src/transmute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ mod wrong_transmute;
use clippy_config::Conf;
use clippy_utils::is_in_const_context;
use clippy_utils::msrvs::Msrv;
use clippy_utils::sugg::Sugg;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;

Expand Down Expand Up @@ -465,6 +467,30 @@ declare_clippy_lint! {
"warns if a transmute call doesn't have all generics specified"
}

/// When transmuting, a struct containing a single field works like the field.
/// This function extracts the field type and the expression to get the field.
fn extract_struct_field<'tcx>(
cx: &LateContext<'tcx>,
outer_type: Ty<'tcx>,
outer: &'tcx Expr<'tcx>,
) -> (Ty<'tcx>, Option<Sugg<'tcx>>) {
let outer_sugg = Sugg::hir_opt(cx, outer);
if let ty::Adt(struct_def, struct_args) = *outer_type.kind()
&& struct_def.is_struct()
&& let mut fields = struct_def.all_fields()
&& let Some(first) = fields.next()
&& fields.next().is_none()
&& first.vis.is_accessible_from(cx.tcx.parent_module(outer.hir_id), cx.tcx)
{
(
first.ty(cx.tcx, struct_args),
outer_sugg.map(|outer| Sugg::NonParen(format!("{}.{}", outer.maybe_paren(), first.name).into())),
)
} else {
(outer_type, outer_sugg)
}
}

pub struct Transmute {
msrv: Msrv,
}
Expand Down Expand Up @@ -515,14 +541,17 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
return;
}

// A struct having a single pointer can be treated like a pointer.
let (from_field_ty, from_field_expr) = extract_struct_field(cx, from_ty, arg);

let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
| transmuting_null::check(cx, e, arg, to_ty)
| transmute_null_to_fn::check(cx, e, arg, to_ty)
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
| transmute_ptr_to_ref::check(cx, e, from_field_ty, to_ty, from_field_expr.clone(), path, self.msrv)
| missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id)
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv)
| transmute_ptr_to_ptr::check(cx, e, from_field_ty, to_ty, from_field_expr, self.msrv)
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
| transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
| (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
arg: Option<sugg::Sugg<'_>>,
msrv: Msrv,
) -> bool {
match (from_ty.kind(), to_ty.kind()) {
Expand All @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
e.span,
"transmute from a pointer to a pointer",
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
if let Some(arg) = arg {
if from_mutbl == to_mutbl
&& to_pointee_ty.is_sized(cx.tcx, cx.typing_env())
&& msrv.meets(cx, msrvs::POINTER_CAST)
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/transmute/transmute_ptr_to_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
arg: Option<sugg::Sugg<'_>>,
path: &'tcx Path<'_>,
msrv: Msrv,
) -> bool {
Expand All @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
e.span,
format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
let arg = arg.unwrap_or(sugg::Sugg::NonParen("..".into()));
let (deref, cast) = match mutbl {
Mutability::Mut => ("&mut *", "*mut"),
Mutability::Not => ("&*", "*const"),
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/transmute_ptr_to_ptr.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,23 @@ struct GenericParam<T> {
t: T,
}

#[derive(Clone, Copy)]
struct PtrNamed {
ptr: *const u32,
}
#[derive(Clone, Copy)]
struct Ptr(*const u32);
fn transmute_ptr_to_ptr() {
let ptr = &1u32 as *const u32;
let mut_ptr = &mut 1u32 as *mut u32;
unsafe {
// pointer-to-pointer transmutes; bad
let _: *const f32 = Ptr(ptr).0.cast::<f32>();
//~^ transmute_ptr_to_ptr
let _: *const f32 = ptr.cast::<f32>();
//~^ transmute_ptr_to_ptr
let _: *const f32 = PtrNamed { ptr }.ptr.cast::<f32>();
//~^ transmute_ptr_to_ptr

let _: *mut f32 = mut_ptr.cast::<f32>();
//~^ transmute_ptr_to_ptr
Expand Down Expand Up @@ -59,6 +69,8 @@ fn transmute_ptr_to_ptr() {

let _: *mut u32 = ptr.cast_mut();
//~^ transmute_ptr_to_ptr
let _: *mut u32 = Ptr(ptr).0.cast_mut();
//~^ transmute_ptr_to_ptr
}

// transmute internal lifetimes, should not lint
Expand All @@ -81,9 +93,13 @@ const _: &() = {
unsafe { transmute::<&'static Zst, &'static ()>(zst) }
};

#[derive(Clone, Copy)]
struct Ptr8(*const u8);
#[clippy::msrv = "1.37"]
fn msrv_1_37(ptr: *const u8) {
unsafe {
let _: *const i8 = Ptr8(ptr).0 as *const i8;
//~^ transmute_ptr_to_ptr
let _: *const i8 = ptr as *const i8;
//~^ transmute_ptr_to_ptr
}
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/transmute_ptr_to_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,23 @@ struct GenericParam<T> {
t: T,
}

#[derive(Clone, Copy)]
struct PtrNamed {
ptr: *const u32,
}
#[derive(Clone, Copy)]
struct Ptr(*const u32);
fn transmute_ptr_to_ptr() {
let ptr = &1u32 as *const u32;
let mut_ptr = &mut 1u32 as *mut u32;
unsafe {
// pointer-to-pointer transmutes; bad
let _: *const f32 = transmute(Ptr(ptr));
//~^ transmute_ptr_to_ptr
let _: *const f32 = transmute(ptr);
//~^ transmute_ptr_to_ptr
let _: *const f32 = transmute(PtrNamed { ptr });
//~^ transmute_ptr_to_ptr

let _: *mut f32 = transmute(mut_ptr);
//~^ transmute_ptr_to_ptr
Expand Down Expand Up @@ -59,6 +69,8 @@ fn transmute_ptr_to_ptr() {

let _: *mut u32 = transmute(ptr);
//~^ transmute_ptr_to_ptr
let _: *mut u32 = transmute(Ptr(ptr));
//~^ transmute_ptr_to_ptr
}

// transmute internal lifetimes, should not lint
Expand All @@ -81,9 +93,13 @@ const _: &() = {
unsafe { transmute::<&'static Zst, &'static ()>(zst) }
};

#[derive(Clone, Copy)]
struct Ptr8(*const u8);
#[clippy::msrv = "1.37"]
fn msrv_1_37(ptr: *const u8) {
unsafe {
let _: *const i8 = transmute(Ptr8(ptr));
//~^ transmute_ptr_to_ptr
let _: *const i8 = transmute(ptr);
//~^ transmute_ptr_to_ptr
}
Expand Down
86 changes: 67 additions & 19 deletions tests/ui/transmute_ptr_to_ptr.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:32:29
--> tests/ui/transmute_ptr_to_ptr.rs:38:29
|
LL | let _: *const f32 = transmute(ptr);
| ^^^^^^^^^^^^^^
LL | let _: *const f32 = transmute(Ptr(ptr));
| ^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ptr)]`
help: use `pointer::cast` instead
|
LL - let _: *const f32 = transmute(Ptr(ptr));
LL + let _: *const f32 = Ptr(ptr).0.cast::<f32>();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:40:29
|
LL | let _: *const f32 = transmute(ptr);
| ^^^^^^^^^^^^^^
|
help: use `pointer::cast` instead
|
LL - let _: *const f32 = transmute(ptr);
LL + let _: *const f32 = ptr.cast::<f32>();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:35:27
--> tests/ui/transmute_ptr_to_ptr.rs:42:29
|
LL | let _: *const f32 = transmute(PtrNamed { ptr });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: use `pointer::cast` instead
|
LL - let _: *const f32 = transmute(PtrNamed { ptr });
LL + let _: *const f32 = PtrNamed { ptr }.ptr.cast::<f32>();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:45:27
|
LL | let _: *mut f32 = transmute(mut_ptr);
| ^^^^^^^^^^^^^^^^^^
Expand All @@ -25,37 +49,37 @@ LL + let _: *mut f32 = mut_ptr.cast::<f32>();
|

error: transmute from a reference to a reference
--> tests/ui/transmute_ptr_to_ptr.rs:39:23
--> tests/ui/transmute_ptr_to_ptr.rs:49:23
|
LL | let _: &f32 = transmute(&1u32);
| ^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)`

error: transmute from a reference to a reference
--> tests/ui/transmute_ptr_to_ptr.rs:42:23
--> tests/ui/transmute_ptr_to_ptr.rs:52:23
|
LL | let _: &f32 = transmute(&1f64);
| ^^^^^^^^^^^^^^^^ help: try: `&*(&1f64 as *const f64 as *const f32)`

error: transmute from a reference to a reference
--> tests/ui/transmute_ptr_to_ptr.rs:47:27
--> tests/ui/transmute_ptr_to_ptr.rs:57:27
|
LL | let _: &mut f32 = transmute(&mut 1u32);
| ^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`

error: transmute from a reference to a reference
--> tests/ui/transmute_ptr_to_ptr.rs:50:37
--> tests/ui/transmute_ptr_to_ptr.rs:60:37
|
LL | let _: &GenericParam<f32> = transmute(&GenericParam { t: 1u32 });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)`

error: transmute from a reference to a reference
--> tests/ui/transmute_ptr_to_ptr.rs:54:27
--> tests/ui/transmute_ptr_to_ptr.rs:64:27
|
LL | let u8_ref: &u8 = transmute(u64_ref);
| ^^^^^^^^^^^^^^^^^^ help: try: `&*(u64_ref as *const u64 as *const u8)`

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:57:29
--> tests/ui/transmute_ptr_to_ptr.rs:67:29
|
LL | let _: *const u32 = transmute(mut_ptr);
| ^^^^^^^^^^^^^^^^^^
Expand All @@ -67,7 +91,7 @@ LL + let _: *const u32 = mut_ptr.cast_const();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:60:27
--> tests/ui/transmute_ptr_to_ptr.rs:70:27
|
LL | let _: *mut u32 = transmute(ptr);
| ^^^^^^^^^^^^^^
Expand All @@ -79,7 +103,19 @@ LL + let _: *mut u32 = ptr.cast_mut();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:72:14
--> tests/ui/transmute_ptr_to_ptr.rs:72:27
|
LL | let _: *mut u32 = transmute(Ptr(ptr));
| ^^^^^^^^^^^^^^^^^^^
|
help: use `pointer::cast_mut` instead
|
LL - let _: *mut u32 = transmute(Ptr(ptr));
LL + let _: *mut u32 = Ptr(ptr).0.cast_mut();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:84:14
|
LL | unsafe { transmute(v) }
| ^^^^^^^^^^^^
Expand All @@ -91,7 +127,19 @@ LL + unsafe { v as *const &() }
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:87:28
--> tests/ui/transmute_ptr_to_ptr.rs:101:28
|
LL | let _: *const i8 = transmute(Ptr8(ptr));
| ^^^^^^^^^^^^^^^^^^^^
|
help: use an `as` cast instead
|
LL - let _: *const i8 = transmute(Ptr8(ptr));
LL + let _: *const i8 = Ptr8(ptr).0 as *const i8;
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:103:28
|
LL | let _: *const i8 = transmute(ptr);
| ^^^^^^^^^^^^^^
Expand All @@ -103,7 +151,7 @@ LL + let _: *const i8 = ptr as *const i8;
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:95:28
--> tests/ui/transmute_ptr_to_ptr.rs:111:28
|
LL | let _: *const i8 = transmute(ptr);
| ^^^^^^^^^^^^^^
Expand All @@ -115,7 +163,7 @@ LL + let _: *const i8 = ptr.cast::<i8>();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:103:26
--> tests/ui/transmute_ptr_to_ptr.rs:119:26
|
LL | let _: *mut u8 = transmute(ptr);
| ^^^^^^^^^^^^^^
Expand All @@ -127,7 +175,7 @@ LL + let _: *mut u8 = ptr as *mut u8;
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:105:28
--> tests/ui/transmute_ptr_to_ptr.rs:121:28
|
LL | let _: *const u8 = transmute(mut_ptr);
| ^^^^^^^^^^^^^^^^^^
Expand All @@ -139,7 +187,7 @@ LL + let _: *const u8 = mut_ptr as *const u8;
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:113:26
--> tests/ui/transmute_ptr_to_ptr.rs:129:26
|
LL | let _: *mut u8 = transmute(ptr);
| ^^^^^^^^^^^^^^
Expand All @@ -151,7 +199,7 @@ LL + let _: *mut u8 = ptr.cast_mut();
|

error: transmute from a pointer to a pointer
--> tests/ui/transmute_ptr_to_ptr.rs:115:28
--> tests/ui/transmute_ptr_to_ptr.rs:131:28
|
LL | let _: *const u8 = transmute(mut_ptr);
| ^^^^^^^^^^^^^^^^^^
Expand All @@ -162,5 +210,5 @@ LL - let _: *const u8 = transmute(mut_ptr);
LL + let _: *const u8 = mut_ptr.cast_const();
|

error: aborting due to 16 previous errors
error: aborting due to 20 previous errors

Loading