Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 03ba508

Browse files
authored
Fixes manual_slice_size_computation ICE and triggers in const context (rust-lang#14804)
The first commit fixes rust-lang/rust-clippy#14802: when a slice is directly present, it must be dereferenced (instead of referenced -1 times) before being passed to `mem::size_of_val()`. The second commit triggers the lint in a `const` contact when MSRV ≥ 1.85. changelog: [`manual_slice_size_computation`]: fix ICE in suggestion to efficiently compute the size of a slice, and trigger the lint in `const` context as well
2 parents 5687ed5 + fe4b4e8 commit 03ba508

File tree

8 files changed

+81
-14
lines changed

8 files changed

+81
-14
lines changed

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
836836
* [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n)
837837
* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
838838
* [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill)
839+
* [`manual_slice_size_calculation`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation)
839840
* [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
840841
* [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
841842
* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)

clippy_config/src/conf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ define_Conf! {
739739
manual_repeat_n,
740740
manual_retain,
741741
manual_slice_fill,
742+
manual_slice_size_calculation,
742743
manual_split_once,
743744
manual_str_repeat,
744745
manual_strip,

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
867867
store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
868868
store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf)));
869869
store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
870-
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
870+
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf)));
871871
store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
872872
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
873873
store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));

clippy_lints/src/manual_slice_size_calculation.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use clippy_config::Conf;
12
use clippy_utils::diagnostics::span_lint_and_sugg;
3+
use clippy_utils::msrvs::{self, Msrv};
24
use clippy_utils::source::snippet_with_context;
35
use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
46
use rustc_errors::Applicability;
57
use rustc_hir::{BinOpKind, Expr, ExprKind};
68
use rustc_lint::{LateContext, LateLintPass};
79
use rustc_middle::ty;
8-
use rustc_session::declare_lint_pass;
10+
use rustc_session::impl_lint_pass;
911
use rustc_span::symbol::sym;
1012

1113
declare_clippy_lint! {
@@ -36,20 +38,33 @@ declare_clippy_lint! {
3638
complexity,
3739
"manual slice size calculation"
3840
}
39-
declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
41+
impl_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
42+
43+
pub struct ManualSliceSizeCalculation {
44+
msrv: Msrv,
45+
}
46+
47+
impl ManualSliceSizeCalculation {
48+
pub fn new(conf: &Conf) -> Self {
49+
Self { msrv: conf.msrv }
50+
}
51+
}
4052

4153
impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
4254
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
4355
if let ExprKind::Binary(ref op, left, right) = expr.kind
4456
&& BinOpKind::Mul == op.node
4557
&& !expr.span.from_expansion()
46-
// Does not apply inside const because size_of_val is not cost in stable.
47-
&& !is_in_const_context(cx)
4858
&& let Some((receiver, refs_count)) = simplify(cx, left, right)
59+
&& (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL))
4960
{
5061
let ctxt = expr.span.ctxt();
5162
let mut app = Applicability::MachineApplicable;
52-
let deref = "*".repeat(refs_count - 1);
63+
let deref = if refs_count > 0 {
64+
"*".repeat(refs_count - 1)
65+
} else {
66+
"&".into()
67+
};
5368
let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0;
5469
let Some(sugg) = std_or_core(cx) else { return };
5570

clippy_utils/src/msrvs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ macro_rules! msrv_aliases {
2424
msrv_aliases! {
2525
1,88,0 { LET_CHAINS }
2626
1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
27-
1,85,0 { UINT_FLOAT_MIDPOINT }
27+
1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
2828
1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
2929
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
3030
1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }

tests/ui/manual_slice_size_calculation.fixed

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,26 @@ fn main() {
6060
let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
6161
}
6262

63-
const fn _const(s_i32: &[i32]) {
64-
// True negative:
65-
let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
63+
#[clippy::msrv = "1.85"]
64+
const fn const_ok(s_i32: &[i32]) {
65+
let _ = std::mem::size_of_val(s_i32);
66+
//~^ manual_slice_size_calculation
67+
}
68+
69+
#[clippy::msrv = "1.84"]
70+
const fn const_before_msrv(s_i32: &[i32]) {
71+
let _ = s_i32.len() * size_of::<i32>();
72+
}
73+
74+
fn issue_14802() {
75+
struct IcedSlice {
76+
dst: [u8],
77+
}
78+
79+
impl IcedSlice {
80+
fn get_len(&self) -> usize {
81+
std::mem::size_of_val(&self.dst)
82+
//~^ manual_slice_size_calculation
83+
}
84+
}
6685
}

tests/ui/manual_slice_size_calculation.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,26 @@ fn main() {
6060
let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
6161
}
6262

63-
const fn _const(s_i32: &[i32]) {
64-
// True negative:
65-
let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
63+
#[clippy::msrv = "1.85"]
64+
const fn const_ok(s_i32: &[i32]) {
65+
let _ = s_i32.len() * size_of::<i32>();
66+
//~^ manual_slice_size_calculation
67+
}
68+
69+
#[clippy::msrv = "1.84"]
70+
const fn const_before_msrv(s_i32: &[i32]) {
71+
let _ = s_i32.len() * size_of::<i32>();
72+
}
73+
74+
fn issue_14802() {
75+
struct IcedSlice {
76+
dst: [u8],
77+
}
78+
79+
impl IcedSlice {
80+
fn get_len(&self) -> usize {
81+
self.dst.len() * size_of::<u8>()
82+
//~^ manual_slice_size_calculation
83+
}
84+
}
6685
}

tests/ui/manual_slice_size_calculation.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,17 @@ error: manual slice size calculation
5555
LL | let _ = external!(&[1u64][..]).len() * size_of::<u64>();
5656
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))`
5757

58-
error: aborting due to 9 previous errors
58+
error: manual slice size calculation
59+
--> tests/ui/manual_slice_size_calculation.rs:65:13
60+
|
61+
LL | let _ = s_i32.len() * size_of::<i32>();
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
63+
64+
error: manual slice size calculation
65+
--> tests/ui/manual_slice_size_calculation.rs:81:13
66+
|
67+
LL | self.dst.len() * size_of::<u8>()
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)`
69+
70+
error: aborting due to 11 previous errors
5971

0 commit comments

Comments
 (0)