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
66 changes: 33 additions & 33 deletions clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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,
);
}
},
);
Expand Down
42 changes: 19 additions & 23 deletions clippy_lints/src/transmute/transmute_ref_to_ref.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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()
Expand All @@ -29,48 +27,46 @@ 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,
e.span,
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,
TRANSMUTE_PTR_TO_PTR,
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
}
13 changes: 13 additions & 0 deletions tests/ui/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
8 changes: 7 additions & 1 deletion tests/ui/transmute.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

20 changes: 20 additions & 0 deletions tests/ui/transmute_ref_to_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
20 changes: 19 additions & 1 deletion tests/ui/transmute_ref_to_ref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f32>();
|

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