Skip to content

Fixes manual_slice_size_computation ICE and triggers in const context #14804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/src/lint_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
* [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n)
* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
* [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill)
* [`manual_slice_size_calculation`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation)
* [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
* [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
Expand Down
1 change: 1 addition & 0 deletions clippy_config/src/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,7 @@ define_Conf! {
manual_repeat_n,
manual_retain,
manual_slice_fill,
manual_slice_size_calculation,
manual_split_once,
manual_str_repeat,
manual_strip,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf)));
store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf)));
store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
Expand Down
25 changes: 20 additions & 5 deletions clippy_lints/src/manual_slice_size_calculation.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;

declare_clippy_lint! {
Expand Down Expand Up @@ -36,20 +38,33 @@ declare_clippy_lint! {
complexity,
"manual slice size calculation"
}
declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
impl_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);

pub struct ManualSliceSizeCalculation {
msrv: Msrv,
}

impl ManualSliceSizeCalculation {
pub fn new(conf: &Conf) -> Self {
Self { msrv: conf.msrv }
}
}

impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::Binary(ref op, left, right) = expr.kind
&& BinOpKind::Mul == op.node
&& !expr.span.from_expansion()
// Does not apply inside const because size_of_val is not cost in stable.
&& !is_in_const_context(cx)
&& let Some((receiver, refs_count)) = simplify(cx, left, right)
&& (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL))
{
let ctxt = expr.span.ctxt();
let mut app = Applicability::MachineApplicable;
let deref = "*".repeat(refs_count - 1);
let deref = if refs_count > 0 {
"*".repeat(refs_count - 1)
} else {
"&".into()
};
let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0;
let Some(sugg) = std_or_core(cx) else { return };

Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/msrvs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ macro_rules! msrv_aliases {
msrv_aliases! {
1,88,0 { LET_CHAINS }
1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
1,85,0 { UINT_FLOAT_MIDPOINT }
1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
Expand Down
25 changes: 22 additions & 3 deletions tests/ui/manual_slice_size_calculation.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,26 @@ fn main() {
let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
}

const fn _const(s_i32: &[i32]) {
// True negative:
let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
#[clippy::msrv = "1.85"]
const fn const_ok(s_i32: &[i32]) {
let _ = std::mem::size_of_val(s_i32);
//~^ manual_slice_size_calculation
}

#[clippy::msrv = "1.84"]
const fn const_before_msrv(s_i32: &[i32]) {
let _ = s_i32.len() * size_of::<i32>();
}

fn issue_14802() {
struct IcedSlice {
dst: [u8],
}

impl IcedSlice {
fn get_len(&self) -> usize {
std::mem::size_of_val(&self.dst)
//~^ manual_slice_size_calculation
}
}
}
25 changes: 22 additions & 3 deletions tests/ui/manual_slice_size_calculation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,26 @@ fn main() {
let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
}

const fn _const(s_i32: &[i32]) {
// True negative:
let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
#[clippy::msrv = "1.85"]
const fn const_ok(s_i32: &[i32]) {
let _ = s_i32.len() * size_of::<i32>();
//~^ manual_slice_size_calculation
}

#[clippy::msrv = "1.84"]
const fn const_before_msrv(s_i32: &[i32]) {
let _ = s_i32.len() * size_of::<i32>();
}

fn issue_14802() {
struct IcedSlice {
dst: [u8],
}

impl IcedSlice {
fn get_len(&self) -> usize {
self.dst.len() * size_of::<u8>()
//~^ manual_slice_size_calculation
}
}
}
14 changes: 13 additions & 1 deletion tests/ui/manual_slice_size_calculation.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,17 @@ error: manual slice size calculation
LL | let _ = external!(&[1u64][..]).len() * size_of::<u64>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))`

error: aborting due to 9 previous errors
error: manual slice size calculation
--> tests/ui/manual_slice_size_calculation.rs:65:13
|
LL | let _ = s_i32.len() * size_of::<i32>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`

error: manual slice size calculation
--> tests/ui/manual_slice_size_calculation.rs:81:13
|
LL | self.dst.len() * size_of::<u8>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)`

error: aborting due to 11 previous errors

Loading