Skip to content

Commit af9dfa3

Browse files
committed
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
1 parent c922bb9 commit af9dfa3

File tree

3 files changed

+113
-56
lines changed

3 files changed

+113
-56
lines changed

clippy_lints/src/casts/cast_slice_different_sizes.rs

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,6 @@ use rustc_semver::RustcVersion;
88

99
use super::CAST_SLICE_DIFFERENT_SIZES;
1010

11-
fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
12-
let map = cx.tcx.hir();
13-
if_chain! {
14-
if let Some(parent_id) = map.find_parent_node(expr.hir_id);
15-
if let Some(parent) = map.find(parent_id);
16-
then {
17-
let expr = match parent {
18-
Node::Block(block) => {
19-
if let Some(parent_expr) = block.expr {
20-
parent_expr
21-
} else {
22-
return false;
23-
}
24-
},
25-
Node::Expr(expr) => expr,
26-
_ => return false,
27-
};
28-
29-
matches!(expr.kind, ExprKind::Cast(..))
30-
} else {
31-
false
32-
}
33-
}
34-
}
35-
3611
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
3712
// suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
3813
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
4520
return;
4621
}
4722

48-
if let Some((from_slice_ty, to_slice_ty)) = expr_cast_chain_tys(cx, expr) {
49-
if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(from_slice_ty.ty), cx.layout_of(to_slice_ty.ty)) {
23+
if let Some(CastChainInfo {
24+
left_cast,
25+
start_ty,
26+
end_ty,
27+
}) = expr_cast_chain_tys(cx, expr)
28+
{
29+
if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) {
5030
let from_size = from_layout.size.bytes();
5131
let to_size = to_layout.size.bytes();
5232
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
5636
expr.span,
5737
&format!(
5838
"casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count",
59-
from_slice_ty, from_size, to_slice_ty, to_size,
39+
start_ty.ty, from_size, end_ty.ty, to_size,
6040
),
6141
|diag| {
62-
let cast_expr = match expr.peel_blocks().kind {
63-
ExprKind::Cast(cast_expr, ..) => cast_expr,
64-
_ => unreachable!("expr should be a cast as checked by expr_cast_chain_tys"),
65-
};
66-
let ptr_snippet = snippet_opt(cx, cast_expr.span).unwrap();
42+
let ptr_snippet = snippet_opt(cx, left_cast.span).unwrap();
6743

68-
let (mutbl_fn_str, mutbl_ptr_str) = match to_slice_ty.mutbl {
44+
let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl {
6945
Mutability::Mut => ("_mut", "mut"),
7046
Mutability::Not => ("", "const"),
7147
};
7248
let sugg = format!(
73-
"core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {to_slice_ty}, ..)"
49+
"core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)",
50+
// get just the ty from the TypeAndMut so that the printed type isn't something like `mut
51+
// T`, extract just the `T`
52+
end_ty.ty
7453
);
7554

7655
diag.span_suggestion(
@@ -86,6 +65,31 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
8665
}
8766
}
8867

68+
fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
69+
let map = cx.tcx.hir();
70+
if_chain! {
71+
if let Some(parent_id) = map.find_parent_node(expr.hir_id);
72+
if let Some(parent) = map.find(parent_id);
73+
then {
74+
let expr = match parent {
75+
Node::Block(block) => {
76+
if let Some(parent_expr) = block.expr {
77+
parent_expr
78+
} else {
79+
return false;
80+
}
81+
},
82+
Node::Expr(expr) => expr,
83+
_ => return false,
84+
};
85+
86+
matches!(expr.kind, ExprKind::Cast(..))
87+
} else {
88+
false
89+
}
90+
}
91+
}
92+
8993
/// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if
9094
/// the type is one of those slices
9195
fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
@@ -98,18 +102,43 @@ fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
98102
}
99103
}
100104

101-
/// Returns the pair (original ptr T, final ptr U) if the expression is composed of casts
105+
struct CastChainInfo<'expr, 'tcx> {
106+
/// The left most part of the cast chain, or in other words, the first cast in the chain
107+
/// Used for diagnostics
108+
left_cast: &'expr Expr<'expr>,
109+
/// The starting type of the cast chain
110+
start_ty: TypeAndMut<'tcx>,
111+
/// The final type of the cast chain
112+
end_ty: TypeAndMut<'tcx>,
113+
}
114+
115+
// FIXME(asquared31415): unbounded recursion linear with the number of casts in an expression
116+
/// Returns a `CastChainInfo` with the left-most cast in the chain and the original ptr T and final
117+
/// ptr U if the expression is composed of casts.
102118
/// Returns None if the expr is not a Cast
103-
fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<(TypeAndMut<'tcx>, TypeAndMut<'tcx>)> {
119+
fn expr_cast_chain_tys<'tcx, 'expr>(cx: &LateContext<'tcx>, expr: &Expr<'expr>) -> Option<CastChainInfo<'expr, 'tcx>> {
104120
if let ExprKind::Cast(cast_expr, _cast_to_hir_ty) = expr.peel_blocks().kind {
105121
let cast_to = cx.typeck_results().expr_ty(expr);
106122
let to_slice_ty = get_raw_slice_ty_mut(cast_to)?;
107-
if let Some((inner_from_ty, _inner_to_ty)) = expr_cast_chain_tys(cx, cast_expr) {
108-
Some((inner_from_ty, to_slice_ty))
123+
if let Some(CastChainInfo {
124+
left_cast,
125+
start_ty,
126+
end_ty: _,
127+
}) = expr_cast_chain_tys(cx, cast_expr)
128+
{
129+
Some(CastChainInfo {
130+
left_cast,
131+
start_ty,
132+
end_ty: to_slice_ty,
133+
})
109134
} else {
110135
let cast_from = cx.typeck_results().expr_ty(cast_expr);
111136
let from_slice_ty = get_raw_slice_ty_mut(cast_from)?;
112-
Some((from_slice_ty, to_slice_ty))
137+
Some(CastChainInfo {
138+
left_cast: cast_expr,
139+
start_ty: from_slice_ty,
140+
end_ty: to_slice_ty,
141+
})
113142
}
114143
} else {
115144
None

tests/ui/cast_slice_different_sizes.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ fn bar2(x: *mut [u16]) -> *mut [u8] {
6262
x as _
6363
}
6464

65+
// constify
66+
fn bar3(x: *mut [u16]) -> *const [u8] {
67+
x as _
68+
}
69+
70+
// unconstify
71+
fn bar4(x: *const [u16]) -> *mut [u8] {
72+
x as _
73+
}
74+
6575
// function returns plus blocks
6676
fn blocks(x: *mut [u16]) -> *mut [u8] {
6777
({ x }) as _

tests/ui/cast_slice_different_sizes.stderr

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,58 +46,76 @@ error: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (elem
4646
--> $DIR/cast_slice_different_sizes.rs:38:27
4747
|
4848
LL | let long_chain_loss = r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8];
49-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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, ..)`
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(r_x as *const [i32] as *const u8, ..)`
5050

51-
error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
51+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
5252
--> $DIR/cast_slice_different_sizes.rs:53:36
5353
|
5454
LL | fn bar(x: *mut [u16]) -> *mut [u8] {
5555
| ____________________________________^
5656
LL | | x as *mut [u8]
5757
LL | | }
58-
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut mut u8, ..)`
58+
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
5959

60-
error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
60+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
6161
--> $DIR/cast_slice_different_sizes.rs:57:36
6262
|
6363
LL | fn uwu(x: *mut [u16]) -> *mut [u8] {
6464
| ____________________________________^
6565
LL | | x as *mut _
6666
LL | | }
67-
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut mut u8, ..)`
67+
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
6868

69-
error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
69+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
7070
--> $DIR/cast_slice_different_sizes.rs:61:37
7171
|
7272
LL | fn bar2(x: *mut [u16]) -> *mut [u8] {
7373
| _____________________________________^
7474
LL | | x as _
7575
LL | | }
76-
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut mut u8, ..)`
76+
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
7777

78-
error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
78+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
7979
--> $DIR/cast_slice_different_sizes.rs:66:39
8080
|
81+
LL | fn bar3(x: *mut [u16]) -> *const [u8] {
82+
| _______________________________________^
83+
LL | | x as _
84+
LL | | }
85+
| |_^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(x as *const u8, ..)`
86+
87+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
88+
--> $DIR/cast_slice_different_sizes.rs:71:39
89+
|
90+
LL | fn bar4(x: *const [u16]) -> *mut [u8] {
91+
| _______________________________________^
92+
LL | | x as _
93+
LL | | }
94+
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
95+
96+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
97+
--> $DIR/cast_slice_different_sizes.rs:76:39
98+
|
8199
LL | fn blocks(x: *mut [u16]) -> *mut [u8] {
82100
| _______________________________________^
83101
LL | | ({ x }) as _
84102
LL | | }
85-
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut mut u8, ..)`
103+
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
86104

87-
error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
88-
--> $DIR/cast_slice_different_sizes.rs:70:44
105+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
106+
--> $DIR/cast_slice_different_sizes.rs:80:44
89107
|
90108
LL | fn more_blocks(x: *mut [u16]) -> *mut [u8] {
91109
| ____________________________________________^
92110
LL | | { ({ x }) as _ }
93111
LL | | }
94-
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut mut u8, ..)`
112+
| |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
95113

96-
error: casting between raw pointers to `[mut u16]` (element size 2) and `[mut u8]` (element size 1) does not adjust the count
97-
--> $DIR/cast_slice_different_sizes.rs:71:5
114+
error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
115+
--> $DIR/cast_slice_different_sizes.rs:81:5
98116
|
99117
LL | { ({ x }) as _ }
100-
| ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut mut u8, ..)`
118+
| ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
101119

102-
error: aborting due to 12 previous errors
120+
error: aborting due to 14 previous errors
103121

0 commit comments

Comments
 (0)