diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 933e25fe98c6..91fce5d5bd68 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -17,6 +17,8 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, msrv: Msrv, ) -> bool { + let mut applicability = Applicability::MachineApplicable; + let arg_sugg = sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut applicability); match (from_ty.kind(), to_ty.kind()) { (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => { span_lint_and_then( @@ -25,40 +27,38 @@ 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 from_mutbl == to_mutbl - && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) - && msrv.meets(cx, msrvs::POINTER_CAST) - { - diag.span_suggestion_verbose( - e.span, - "use `pointer::cast` instead", - format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()), - Applicability::MaybeIncorrect, - ); - } else if from_pointee_ty == to_pointee_ty - && let Some(method) = match (from_mutbl, to_mutbl) { - (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"), - (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"), - _ => None, - } - && !from_pointee_ty.has_erased_regions() - && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) - { - diag.span_suggestion_verbose( - e.span, - format!("use `pointer::{method}` instead"), - format!("{}.{method}()", arg.maybe_paren()), - Applicability::MaybeIncorrect, - ); - } else { - diag.span_suggestion_verbose( - e.span, - "use an `as` cast instead", - arg.as_ty(to_ty), - Applicability::MaybeIncorrect, - ); + if from_mutbl == to_mutbl + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) + && msrv.meets(cx, msrvs::POINTER_CAST) + { + diag.span_suggestion_verbose( + e.span, + "use `pointer::cast` instead", + format!("{}.cast::<{to_pointee_ty}>()", arg_sugg.maybe_paren()), + Applicability::MaybeIncorrect, + ); + } else if from_pointee_ty == to_pointee_ty + && let Some(method) = match (from_mutbl, to_mutbl) { + (ty::Mutability::Not, ty::Mutability::Mut) => Some("cast_mut"), + (ty::Mutability::Mut, ty::Mutability::Not) => Some("cast_const"), + _ => None, } + && !from_pointee_ty.has_erased_regions() + && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) + { + diag.span_suggestion_verbose( + e.span, + format!("use `pointer::{method}` instead"), + format!("{}.{method}()", arg_sugg.maybe_paren()), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_suggestion_verbose( + e.span, + "use an `as` cast instead", + arg_sugg.as_ty(to_ty), + Applicability::MaybeIncorrect, + ); } }, ); diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 70c2a73ce6ef..39b1ccdc9426 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -1,6 +1,5 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; use clippy_utils::{std_or_core, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -17,8 +16,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, const_context: bool, ) -> bool { - let mut triggered = false; - + let arg_sugg = || sugg::Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut Applicability::Unspecified); if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (*from_ty.kind(), *to_ty.kind()) { if let ty::Slice(slice_ty) = *ty_from.kind() && ty_to.is_str() @@ -29,8 +27,6 @@ pub(super) fn check<'tcx>( let postfix = if from_mutbl == Mutability::Mut { "_mut" } else { "" }; - let snippet = snippet(cx, arg.span, ".."); - span_lint_and_sugg( cx, TRANSMUTE_BYTES_TO_STR, @@ -38,15 +34,17 @@ pub(super) fn check<'tcx>( format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { - format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") + format!("{top_crate}::str::from_utf8_unchecked{postfix}({})", arg_sugg()) } else { - format!("{top_crate}::str::from_utf8{postfix}({snippet}).unwrap()") + format!("{top_crate}::str::from_utf8{postfix}({}).unwrap()", arg_sugg()) }, Applicability::MaybeIncorrect, ); - triggered = true; - } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) - && !const_context + + return true; + } + + if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context { span_lint_and_then( cx, @@ -54,23 +52,21 @@ pub(super) fn check<'tcx>( e.span, "transmute from a reference to a reference", |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg_paren = arg - .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) - .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); - let sugg = if to_mutbl == Mutability::Mut { - sugg_paren.mut_addr_deref() - } else { - sugg_paren.addr_deref() - }; - diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); - } + let sugg_paren = arg_sugg() + .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl)) + .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl)); + let sugg = if to_mutbl == Mutability::Mut { + sugg_paren.mut_addr_deref() + } else { + sugg_paren.addr_deref() + }; + diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); }, ); - triggered = true; + return true; } } - triggered + false } diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index e7099104f942..afb79deac20f 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -128,4 +128,17 @@ fn bytes_to_str(mb: &mut [u8]) { //~^ transmute_bytes_to_str } +fn issue16104() { + let b = vec![1_u8, 2_u8]; + macro_rules! take_ref { + ($x:expr) => { + $x.as_slice() + }; + } + unsafe { + let _: &str = std::mem::transmute(take_ref!(b)); + //~^ transmute_bytes_to_str + } +} + fn main() {} diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 9478db09481a..6f9a0b717fc9 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -106,5 +106,11 @@ error: transmute from a `&[u8]` to a `&str` LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 16 previous errors +error: transmute from a `&[u8]` to a `&str` + --> tests/ui/transmute.rs:139:23 + | +LL | let _: &str = std::mem::transmute(take_ref!(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(take_ref!(b)).unwrap()` + +error: aborting due to 17 previous errors diff --git a/tests/ui/transmute_ref_to_ref.rs b/tests/ui/transmute_ref_to_ref.rs index 8bdf07b4a428..ed8fb8083291 100644 --- a/tests/ui/transmute_ref_to_ref.rs +++ b/tests/ui/transmute_ref_to_ref.rs @@ -18,3 +18,23 @@ fn main() { //~^ transmute_ptr_to_ptr } } + +fn issue16104(make_ptr: fn() -> *const u32) { + macro_rules! call { + ($x:expr) => { + $x() + }; + } + macro_rules! take_ref { + ($x:expr) => { + &$x + }; + } + + unsafe { + let _: *const f32 = std::mem::transmute(call!(make_ptr)); + //~^ transmute_ptr_to_ptr + let _: &f32 = std::mem::transmute(take_ref!(1u32)); + //~^ transmute_ptr_to_ptr + } +} diff --git a/tests/ui/transmute_ref_to_ref.stderr b/tests/ui/transmute_ref_to_ref.stderr index e8d659f9c5d8..1b845ef859d8 100644 --- a/tests/ui/transmute_ref_to_ref.stderr +++ b/tests/ui/transmute_ref_to_ref.stderr @@ -22,5 +22,23 @@ error: transmute from a reference to a reference LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` -error: aborting due to 3 previous errors +error: transmute from a pointer to a pointer + --> tests/ui/transmute_ref_to_ref.rs:35:29 + | +LL | let _: *const f32 = std::mem::transmute(call!(make_ptr)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `pointer::cast` instead + | +LL - let _: *const f32 = std::mem::transmute(call!(make_ptr)); +LL + let _: *const f32 = call!(make_ptr).cast::(); + | + +error: transmute from a reference to a reference + --> tests/ui/transmute_ref_to_ref.rs:37:23 + | +LL | let _: &f32 = std::mem::transmute(take_ref!(1u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(take_ref!(1u32) as *const u32 as *const f32)` + +error: aborting due to 5 previous errors