about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/transmute/transmute_ptr_to_ref.rs44
-rw-r--r--tests/ui/transmute_ptr_to_ref.fixed39
-rw-r--r--tests/ui/transmute_ptr_to_ref.rs39
-rw-r--r--tests/ui/transmute_ptr_to_ref.stderr54
4 files changed, 150 insertions, 26 deletions
diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index e58212fae15..e67ab6a73d2 100644
--- a/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -28,16 +28,27 @@ 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()
@@ -45,15 +56,22 @@ pub(super) fn check<'tcx>(
                             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()
diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed
index 61e3ac2fe88..c130575df96 100644
--- a/tests/ui/transmute_ptr_to_ref.fixed
+++ b/tests/ui/transmute_ptr_to_ref.fixed
@@ -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
@@ -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,
     }
@@ -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>(),
@@ -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;
@@ -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;
@@ -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() {}
diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs
index 48e2f527b55..f79d54234a2 100644
--- a/tests/ui/transmute_ptr_to_ref.rs
+++ b/tests/ui/transmute_ptr_to_ref.rs
@@ -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
@@ -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,
     }
@@ -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),
@@ -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;
@@ -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;
@@ -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() {}
diff --git a/tests/ui/transmute_ptr_to_ref.stderr b/tests/ui/transmute_ptr_to_ref.stderr
index 7685c345c86..3f404d295fe 100644
--- a/tests/ui/transmute_ptr_to_ref.stderr
+++ b/tests/ui/transmute_ptr_to_ref.stderr
@@ -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) };
@@ -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