mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 21:47:04 +00:00
Auto merge of #8720 - asquared31415:ptr-cast-ice-fix, r=Alexendoo,xFrednet
fix ICE in `cast_slice_different_sizes` fixes #8708 changelog: fixes an ICE introduced in #8445
This commit is contained in:
commit
ec46992008
@ -1,4 +1,4 @@
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source::snippet_opt};
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::{Expr, ExprKind, Node};
|
||||
@ -8,6 +8,63 @@ use rustc_semver::RustcVersion;
|
||||
|
||||
use super::CAST_SLICE_DIFFERENT_SIZES;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if this cast is the child of another cast expression then don't emit something for it, the full
|
||||
// chain will be analyzed
|
||||
if is_child_of_cast(cx, expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CAST_SLICE_DIFFERENT_SIZES,
|
||||
expr.span,
|
||||
&format!(
|
||||
"casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count",
|
||||
start_ty.ty, from_size, end_ty.ty, to_size,
|
||||
),
|
||||
|diag| {
|
||||
let ptr_snippet = source::snippet(cx, left_cast.span, "..");
|
||||
|
||||
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} {}, ..)",
|
||||
// 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(
|
||||
expr.span,
|
||||
&format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
|
||||
sugg,
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let map = cx.tcx.hir();
|
||||
if_chain! {
|
||||
@ -33,59 +90,6 @@ fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if this cast is the child of another cast expression then don't emit something for it, the full
|
||||
// chain will be analyzed
|
||||
if is_child_of_cast(cx, expr) {
|
||||
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)) {
|
||||
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 {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CAST_SLICE_DIFFERENT_SIZES,
|
||||
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,
|
||||
),
|
||||
|diag| {
|
||||
let cast_expr = match expr.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 (mutbl_fn_str, mutbl_ptr_str) = match to_slice_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}, ..)"
|
||||
);
|
||||
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
&format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
|
||||
sugg,
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,40 @@ 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<'tcx> {
|
||||
/// The left most part of the cast chain, or in other words, the first cast in the chain
|
||||
/// Used for diagnostics
|
||||
left_cast: &'tcx Expr<'tcx>,
|
||||
/// The starting type of the cast chain
|
||||
start_ty: TypeAndMut<'tcx>,
|
||||
/// The final type of the cast chain
|
||||
end_ty: TypeAndMut<'tcx>,
|
||||
}
|
||||
|
||||
/// 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>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<CastChainInfo<'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 the expression that makes up the source of this cast is itself a cast, recursively
|
||||
// call `expr_cast_chain_tys` and update the end type with the final tartet type.
|
||||
// Otherwise, this cast is not immediately nested, just construct the info for this cast
|
||||
if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) {
|
||||
Some(CastChainInfo {
|
||||
end_ty: to_slice_ty,
|
||||
..prev_info
|
||||
})
|
||||
} 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
|
||||
|
@ -39,3 +39,44 @@ fn main() {
|
||||
let long_chain_restore =
|
||||
r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8] as *const [u32];
|
||||
}
|
||||
|
||||
// foo and foo2 should not fire, they're the same size
|
||||
fn foo(x: *mut [u8]) -> *mut [u8] {
|
||||
x as *mut [u8]
|
||||
}
|
||||
|
||||
fn foo2(x: *mut [u8]) -> *mut [u8] {
|
||||
x as *mut _
|
||||
}
|
||||
|
||||
// Test that casts as part of function returns work
|
||||
fn bar(x: *mut [u16]) -> *mut [u8] {
|
||||
x as *mut [u8]
|
||||
}
|
||||
|
||||
fn uwu(x: *mut [u16]) -> *mut [u8] {
|
||||
x as *mut _
|
||||
}
|
||||
|
||||
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 _
|
||||
}
|
||||
|
||||
fn more_blocks(x: *mut [u16]) -> *mut [u8] {
|
||||
{ ({ x }) as _ }
|
||||
}
|
||||
|
@ -46,7 +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: aborting due to 6 previous errors
|
||||
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 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: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 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: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 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: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 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: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 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:81:5
|
||||
|
|
||||
LL | { ({ x }) as _ }
|
||||
| ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user