about summary refs log tree commit diff
diff options
context:
space:
mode:
authorasquared31415 <34665709+asquared31415@users.noreply.github.com>2022-04-23 12:49:40 -0400
committerasquared31415 <34665709+asquared31415@users.noreply.github.com>2022-04-23 13:07:13 -0400
commitaf9dfa36921a66116e2cbd4a2aeb8f8f7e0082e9 (patch)
tree23eb6835408957b9cadbcfbbbdd55c8d307d9db2
parentc922bb9443993df9f32ebf25bed76195cfab11f2 (diff)
downloadrust-af9dfa36921a66116e2cbd4a2aeb8f8f7e0082e9.tar.gz
rust-af9dfa36921a66116e2cbd4a2aeb8f8f7e0082e9.zip
fix ICE by using a type to return the info we want and also fix some bugs in displaying an extra mut when a TypeAndMut was wrong
-rw-r--r--clippy_lints/src/casts/cast_slice_different_sizes.rs109
-rw-r--r--tests/ui/cast_slice_different_sizes.rs10
-rw-r--r--tests/ui/cast_slice_different_sizes.stderr50
3 files changed, 113 insertions, 56 deletions
diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs
index ff03f416d0b..893af60db2c 100644
--- a/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -8,31 +8,6 @@ use rustc_semver::RustcVersion;
 
 use super::CAST_SLICE_DIFFERENT_SIZES;
 
-fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let map = cx.tcx.hir();
-    if_chain! {
-        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
-        if let Some(parent) = map.find(parent_id);
-        then {
-            let expr = match parent {
-                Node::Block(block) => {
-                    if let Some(parent_expr) = block.expr {
-                        parent_expr
-                    } else {
-                        return false;
-                    }
-                },
-                Node::Expr(expr) => expr,
-                _ => return false,
-            };
-
-            matches!(expr.kind, ExprKind::Cast(..))
-        } else {
-            false
-        }
-    }
-}
-
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
     // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
     if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) {
@@ -45,8 +20,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
         return;
     }
 
-    if let Some((from_slice_ty, to_slice_ty)) = expr_cast_chain_tys(cx, expr) {
-        if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(from_slice_ty.ty), cx.layout_of(to_slice_ty.ty)) {
+    if let Some(CastChainInfo {
+        left_cast,
+        start_ty,
+        end_ty,
+    }) = expr_cast_chain_tys(cx, expr)
+    {
+        if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) {
             let from_size = from_layout.size.bytes();
             let to_size = to_layout.size.bytes();
             if from_size != to_size && from_size != 0 && to_size != 0 {
@@ -56,21 +36,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
                     expr.span,
                     &format!(
                         "casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count",
-                        from_slice_ty, from_size, to_slice_ty, to_size,
+                        start_ty.ty, from_size, end_ty.ty, to_size,
                     ),
                     |diag| {
-                        let cast_expr = match expr.peel_blocks().kind {
-                            ExprKind::Cast(cast_expr, ..) => cast_expr,
-                            _ => unreachable!("expr should be a cast as checked by expr_cast_chain_tys"),
-                        };
-                        let ptr_snippet = snippet_opt(cx, cast_expr.span).unwrap();
+                        let ptr_snippet = snippet_opt(cx, left_cast.span).unwrap();
 
-                        let (mutbl_fn_str, mutbl_ptr_str) = match to_slice_ty.mutbl {
+                        let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl {
                             Mutability::Mut => ("_mut", "mut"),
                             Mutability::Not => ("", "const"),
                         };
                         let sugg = format!(
-                            "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {to_slice_ty}, ..)"
+                            "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)",
+                            // get just the ty from the TypeAndMut so that the printed type isn't something like `mut
+                            // T`, extract just the `T`
+                            end_ty.ty
                         );
 
                         diag.span_suggestion(
@@ -86,6 +65,31 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
     }
 }
 
+fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let map = cx.tcx.hir();
+    if_chain! {
+        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
+        if let Some(parent) = map.find(parent_id);
+        then {
+            let expr = match parent {
+                Node::Block(block) => {
+                    if let Some(parent_expr) = block.expr {
+                        parent_expr
+                    } else {
+                        return false;
+                    }
+                },
+                Node::Expr(expr) => expr,
+                _ => return false,
+            };
+
+            matches!(expr.kind, ExprKind::Cast(..))
+        } else {
+            false
+        }
+    }
+}
+
 /// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if
 /// the type is one of those slices
 fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
@@ -98,18 +102,43 @@ fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
     }
 }
 
-/// Returns the pair (original ptr T, final ptr U) if the expression is composed of casts
+struct CastChainInfo<'expr, 'tcx> {
+    /// The left most part of the cast chain, or in other words, the first cast in the chain
+    /// Used for diagnostics
+    left_cast: &'expr Expr<'expr>,
+    /// The starting type of the cast chain
+    start_ty: TypeAndMut<'tcx>,
+    /// The final type of the cast chain
+    end_ty: TypeAndMut<'tcx>,
+}
+
+// FIXME(asquared31415): unbounded recursion linear with the number of casts in an expression
+/// Returns a `CastChainInfo` with the left-most cast in the chain and the original ptr T and final
+/// ptr U if the expression is composed of casts.
 /// Returns None if the expr is not a Cast
-fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<(TypeAndMut<'tcx>, TypeAndMut<'tcx>)> {
+fn expr_cast_chain_tys<'tcx, 'expr>(cx: &LateContext<'tcx>, expr: &Expr<'expr>) -> Option<CastChainInfo<'expr, 'tcx>> {
     if let ExprKind::Cast(cast_expr, _cast_to_hir_ty) = expr.peel_blocks().kind {
         let cast_to = cx.typeck_results().expr_ty(expr);
         let to_slice_ty = get_raw_slice_ty_mut(cast_to)?;
-        if let Some((inner_from_ty, _inner_to_ty)) = expr_cast_chain_tys(cx, cast_expr) {
-            Some((inner_from_ty, to_slice_ty))
+        if let Some(CastChainInfo {
+            left_cast,
+            start_ty,
+            end_ty: _,
+        }) = expr_cast_chain_tys(cx, cast_expr)
+        {
+            Some(CastChainInfo {
+                left_cast,
+                start_ty,
+                end_ty: to_slice_ty,
+            })
         } else {
             let cast_from = cx.typeck_results().expr_ty(cast_expr);
             let from_slice_ty = get_raw_slice_ty_mut(cast_from)?;
-            Some((from_slice_ty, to_slice_ty))
+            Some(CastChainInfo {
+                left_cast: cast_expr,
+                start_ty: from_slice_ty,
+                end_ty: to_slice_ty,
+            })
         }
     } else {
         None
diff --git a/tests/ui/cast_slice_different_sizes.rs b/tests/ui/cast_slice_different_sizes.rs
index 7ec137cc5b2..24d7eb28a19 100644
--- a/tests/ui/cast_slice_different_sizes.rs
+++ b/tests/ui/cast_slice_different_sizes.rs
@@ -62,6 +62,16 @@ fn bar2(x: *mut [u16]) -> *mut [u8] {
     x as _
 }
 
+// constify
+fn bar3(x: *mut [u16]) -> *const [u8] {
+    x as _
+}
+
+// unconstify
+fn bar4(x: *const [u16]) -> *mut [u8] {
+    x as _
+}
+
 // function returns plus blocks
 fn blocks(x: *mut [u16]) -> *mut [u8] {
     ({ x }) as _
diff --git a/tests/ui/cast_slice_different_sizes.stderr b/tests/ui/cast_slice_different_sizes.stderr
index 0e018b62e60..40721dcd05d 100644
--- a/tests/ui/cast_slice_different_sizes.stderr
+++ b/tests/ui/cast_slice_different_sizes.stderr
@@ -46,58 +46,76 @@ error: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (elem
   --> $DIR/cast_slice_different_sizes.rs:38:27
    |
 LL |     let long_chain_loss = r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8];
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const u8, ..)`
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(r_x as *const [i32] as *const u8, ..)`
 
-error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
   --> $DIR/cast_slice_different_sizes.rs:53:36
    |
 LL |   fn bar(x: *mut [u16]) -> *mut [u8] {
    |  ____________________________________^
 LL | |     x as *mut [u8]
 LL | | }
-   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut mut u8, ..)`
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
 
-error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
   --> $DIR/cast_slice_different_sizes.rs:57:36
    |
 LL |   fn uwu(x: *mut [u16]) -> *mut [u8] {
    |  ____________________________________^
 LL | |     x as *mut _
 LL | | }
-   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut mut u8, ..)`
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
 
-error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
   --> $DIR/cast_slice_different_sizes.rs:61:37
    |
 LL |   fn bar2(x: *mut [u16]) -> *mut [u8] {
    |  _____________________________________^
 LL | |     x as _
 LL | | }
-   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut mut u8, ..)`
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
 
-error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
   --> $DIR/cast_slice_different_sizes.rs:66:39
    |
+LL |   fn bar3(x: *mut [u16]) -> *const [u8] {
+   |  _______________________________________^
+LL | |     x as _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(x as *const u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:71:39
+   |
+LL |   fn bar4(x: *const [u16]) -> *mut [u8] {
+   |  _______________________________________^
+LL | |     x as _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:76:39
+   |
 LL |   fn blocks(x: *mut [u16]) -> *mut [u8] {
    |  _______________________________________^
 LL | |     ({ x }) as _
 LL | | }
-   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut mut u8, ..)`
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
 
-error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
-  --> $DIR/cast_slice_different_sizes.rs:70:44
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:80:44
    |
 LL |   fn more_blocks(x: *mut [u16]) -> *mut [u8] {
    |  ____________________________________________^
 LL | |     { ({ x }) as _ }
 LL | | }
-   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut mut u8, ..)`
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
 
-error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
-  --> $DIR/cast_slice_different_sizes.rs:71:5
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:81:5
    |
 LL |     { ({ x }) as _ }
-   |     ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut mut u8, ..)`
+   |     ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
 
-error: aborting due to 12 previous errors
+error: aborting due to 14 previous errors