From 4ec219393a48eff84c8c08b854d50a454b8f422c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 14 May 2025 23:17:56 +0200 Subject: [PATCH 1/2] Fix size computation when element is a slice In this case, a dereference is needed before using `mem::size_of_val()`. --- clippy_lints/src/manual_slice_size_calculation.rs | 6 +++++- tests/ui/manual_slice_size_calculation.fixed | 13 +++++++++++++ tests/ui/manual_slice_size_calculation.rs | 13 +++++++++++++ tests/ui/manual_slice_size_calculation.stderr | 8 +++++++- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 2dad0fa4925e..b6a4f44b0e49 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -49,7 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { { 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 }; diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 294d1e1506de..9df5a2ac5cd5 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -64,3 +64,16 @@ const fn _const(s_i32: &[i32]) { // True negative: let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const } + +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 + } + } +} diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index ae5225663139..db14d891c80b 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -64,3 +64,16 @@ const fn _const(s_i32: &[i32]) { // True negative: let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const } + +fn issue_14802() { + struct IcedSlice { + dst: [u8], + } + + impl IcedSlice { + fn get_len(&self) -> usize { + self.dst.len() * size_of::() + //~^ manual_slice_size_calculation + } + } +} diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index f07e97a1c863..00eb32b3e1c3 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -55,5 +55,11 @@ error: manual slice size calculation LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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:75:13 + | +LL | self.dst.len() * size_of::() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)` + +error: aborting due to 10 previous errors From fe4b4e832941b554b802b5ea2bbbe95806c093fe Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 14 May 2025 23:29:17 +0200 Subject: [PATCH 2/2] `mem::size_of_val` is const-stable since Rust 1.85 --- book/src/lint_configuration.md | 1 + clippy_config/src/conf.rs | 1 + clippy_lints/src/lib.rs | 2 +- .../src/manual_slice_size_calculation.rs | 19 +++++++++++++++---- clippy_utils/src/msrvs.rs | 2 +- tests/ui/manual_slice_size_calculation.fixed | 12 +++++++++--- tests/ui/manual_slice_size_calculation.rs | 12 +++++++++--- tests/ui/manual_slice_size_calculation.stderr | 10 ++++++++-- 8 files changed, 45 insertions(+), 14 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 0db4182dbcdb..9809e32de8a4 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -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) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index ad0aea39d41a..4ce8d001c2f0 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -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, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 006145cc623c..ec5227018cea 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -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)); diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index b6a4f44b0e49..0c09a47c9651 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -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! { @@ -36,16 +38,25 @@ 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; diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 223a8649eb3c..ec3de2b9dc8d 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -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 } diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index 9df5a2ac5cd5..090f0fd30c55 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -60,9 +60,15 @@ fn main() { let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) } -const fn _const(s_i32: &[i32]) { - // True negative: - let _ = s_i32.len() * size_of::(); // 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::(); } fn issue_14802() { diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index db14d891c80b..3c19a0eb5cea 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -60,9 +60,15 @@ fn main() { let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) } -const fn _const(s_i32: &[i32]) { - // True negative: - let _ = s_i32.len() * size_of::(); // 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::(); + //~^ manual_slice_size_calculation +} + +#[clippy::msrv = "1.84"] +const fn const_before_msrv(s_i32: &[i32]) { + let _ = s_i32.len() * size_of::(); } fn issue_14802() { diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index 00eb32b3e1c3..8e9b49e4bf29 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -56,10 +56,16 @@ LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:75:13 + --> tests/ui/manual_slice_size_calculation.rs:65:13 + | +LL | let _ = s_i32.len() * size_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)` -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors