Skip to content
Merged
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
44 changes: 31 additions & 13 deletions clippy_lints/src/transmute/transmute_ptr_to_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,32 +28,50 @@ pub(super) fn check<'tcx>(
format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
let (deref, cast) = if *mutbl == Mutability::Mut {
("&mut *", "*mut")
} else {
("&*", "*const")
let (deref, cast) = match mutbl {
Mutability::Mut => ("&mut *", "*mut"),
Mutability::Not => ("&*", "*const"),
};
let mut app = Applicability::MachineApplicable;

let sugg = if let Some(ty) = get_explicit_type(path) {
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
if msrv.meets(cx, msrvs::POINTER_CAST) {
if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
// We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
if from_ptr_ty.has_erased_regions() {
// We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
// thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
// being !Sized.
//
// The only remaining option is be to skip `*mut/const ()`, but that might not be safe
// to do because of the erased regions in `from_ptr_ty`, so reduce the applicability.
app = Applicability::MaybeIncorrect;
}
sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
} else if msrv.meets(cx, msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren())
} else if from_ptr_ty.has_erased_regions() {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
} else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
}
} else if *from_ptr_ty == *to_ref_ty {
if from_ptr_ty.has_erased_regions() {
if msrv.meets(cx, msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
} else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
.to_string()
}
} else {
if !from_ptr_ty.has_erased_regions() {
sugg::make_unop(deref, arg).to_string()
} else if !to_ref_ty.is_sized(cx.tcx, cx.typing_env()) {
// 1. We can't suggest `.cast()`, because that requires `to_ref_ty` to be Sized.
// 2. We can't suggest `as *mut/const () as *mut/const to_ref_ty`, because the former is a
// thin pointer, whereas the latter is a wide pointer, due of its pointee, `to_ref_ty`,
// being !Sized.
//
// The only remaining option is be to skip `*mut/const ()`, but that might not be safe to do
// because of the erased regions in `from_ptr_ty`, so reduce the applicability.
app = Applicability::MaybeIncorrect;
sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
} else if msrv.meets(cx, msrvs::POINTER_CAST) {
format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
} else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))).to_string()
}
} else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
Expand Down
39 changes: 34 additions & 5 deletions tests/ui/transmute_ptr_to_ref.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
clippy::missing_transmute_annotations
)]

unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
unsafe {
let _: &T = &*p;
//~^ transmute_ptr_to_ref
Expand Down Expand Up @@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
}
}

fn _issue1231() {
fn issue1231() {
struct Foo<'a, T> {
bar: &'a T,
}
Expand All @@ -55,7 +55,7 @@ fn _issue1231() {
//~^ transmute_ptr_to_ref
}

unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
unsafe {
match 0 {
0 => &*x.cast::<&u32>(),
Expand All @@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
}

#[clippy::msrv = "1.38"]
unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
unsafe {
let a = 0u32;
let a = &a as *const u32;
Expand All @@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
}

#[clippy::msrv = "1.37"]
unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
unsafe {
let a = 0u32;
let a = &a as *const u32;
Expand All @@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
}
}

// handle DSTs
fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
unsafe {
// different types, without erased regions
let _ = &*(ptr as *const [u32]);
//~^ transmute_ptr_to_ref
let _: &[u32] = &*(ptr as *const [u32]);
//~^ transmute_ptr_to_ref

// different types, with erased regions
let _ = &*(a_s_ptr as *const [&[u8]]);
//~^ transmute_ptr_to_ref
let _: &[&[u8]] = &*(a_s_ptr as *const [&[u8]]);
//~^ transmute_ptr_to_ref

// same type, without erased regions
let _ = &*(ptr as *const [i32]);
//~^ transmute_ptr_to_ref
let _: &[i32] = &*ptr;
//~^ transmute_ptr_to_ref

// same type, with erased regions
let _ = &*(a_s_ptr as *const [&str]);
//~^ transmute_ptr_to_ref
let _: &[&str] = &*(a_s_ptr as *const [&str]);
//~^ transmute_ptr_to_ref
}
}

fn main() {}
39 changes: 34 additions & 5 deletions tests/ui/transmute_ptr_to_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
clippy::missing_transmute_annotations
)]

unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
fn ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
unsafe {
let _: &T = std::mem::transmute(p);
//~^ transmute_ptr_to_ref
Expand Down Expand Up @@ -37,7 +37,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
}
}

fn _issue1231() {
fn issue1231() {
struct Foo<'a, T> {
bar: &'a T,
}
Expand All @@ -55,7 +55,7 @@ fn _issue1231() {
//~^ transmute_ptr_to_ref
}

unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
fn issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
unsafe {
match 0 {
0 => std::mem::transmute(x),
Expand All @@ -71,7 +71,7 @@ unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'
}

#[clippy::msrv = "1.38"]
unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
fn meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
unsafe {
let a = 0u32;
let a = &a as *const u32;
Expand All @@ -89,7 +89,7 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
}

#[clippy::msrv = "1.37"]
unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
fn under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
unsafe {
let a = 0u32;
let a = &a as *const u32;
Expand All @@ -106,4 +106,33 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
}
}

// handle DSTs
fn issue13357(ptr: *const [i32], s_ptr: *const &str, a_s_ptr: *const [&str]) {
unsafe {
// different types, without erased regions
let _ = core::mem::transmute::<_, &[u32]>(ptr);
//~^ transmute_ptr_to_ref
let _: &[u32] = core::mem::transmute(ptr);
//~^ transmute_ptr_to_ref

// different types, with erased regions
let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
//~^ transmute_ptr_to_ref
let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
//~^ transmute_ptr_to_ref

// same type, without erased regions
let _ = core::mem::transmute::<_, &[i32]>(ptr);
//~^ transmute_ptr_to_ref
let _: &[i32] = core::mem::transmute(ptr);
//~^ transmute_ptr_to_ref

// same type, with erased regions
let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
//~^ transmute_ptr_to_ref
let _: &[&str] = core::mem::transmute(a_s_ptr);
//~^ transmute_ptr_to_ref
}
}

fn main() {}
54 changes: 51 additions & 3 deletions tests/ui/transmute_ptr_to_ref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
LL | let _: &T = std::mem::transmute(om);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`

error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`)
--> tests/ui/transmute_ptr_to_ref.rs:46:32
|
LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`

error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`)
--> tests/ui/transmute_ptr_to_ref.rs:49:33
|
LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
Expand Down Expand Up @@ -133,5 +133,53 @@ error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32
LL | _ => std::mem::transmute::<_, &&'b u32>(x),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`

error: aborting due to 22 previous errors
error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
--> tests/ui/transmute_ptr_to_ref.rs:113:17
|
LL | let _ = core::mem::transmute::<_, &[u32]>(ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`

error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[u32]`)
--> tests/ui/transmute_ptr_to_ref.rs:115:25
|
LL | let _: &[u32] = core::mem::transmute(ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [u32])`

error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
--> tests/ui/transmute_ptr_to_ref.rs:119:17
|
LL | let _ = core::mem::transmute::<_, &[&[u8]]>(a_s_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`

error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&[u8]]`)
--> tests/ui/transmute_ptr_to_ref.rs:121:27
|
LL | let _: &[&[u8]] = core::mem::transmute(a_s_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&[u8]])`

error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
--> tests/ui/transmute_ptr_to_ref.rs:125:17
|
LL | let _ = core::mem::transmute::<_, &[i32]>(ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(ptr as *const [i32])`

error: transmute from a pointer type (`*const [i32]`) to a reference type (`&[i32]`)
--> tests/ui/transmute_ptr_to_ref.rs:127:25
|
LL | let _: &[i32] = core::mem::transmute(ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*ptr`

error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
--> tests/ui/transmute_ptr_to_ref.rs:131:17
|
LL | let _ = core::mem::transmute::<_, &[&str]>(a_s_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`

error: transmute from a pointer type (`*const [&str]`) to a reference type (`&[&str]`)
--> tests/ui/transmute_ptr_to_ref.rs:133:26
|
LL | let _: &[&str] = core::mem::transmute(a_s_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a_s_ptr as *const [&str])`

error: aborting due to 30 previous errors