Skip to content

Add new lint suspicious_slice_copies#16671

Open
faeroon wants to merge 2 commits intorust-lang:masterfrom
faeroon:issues/16507
Open

Add new lint suspicious_slice_copies#16671
faeroon wants to merge 2 commits intorust-lang:masterfrom
faeroon:issues/16507

Conversation

@faeroon
Copy link

@faeroon faeroon commented Mar 5, 2026

implements lint for checking usage of a &mut to a temporary array copied from a slice

changelog: [suspicious_slice_copies]

  • Followed lint naming conventions
  • Added passing UI tests (including committed .stderr file)
  • cargo test passes locally
  • Executed cargo dev update_lints
  • Added lint documentation
  • Run cargo dev fmt

Fixes #16507. The lint checks only calls try_into by [T] or &mut [T]. If any other cases should be covered by this lint, please share your feedback.

@rustbot rustbot added the needs-fcp PRs that add, remove, or rename lints and need an FCP label Mar 5, 2026
@faeroon faeroon marked this pull request as ready for review March 5, 2026 22:13
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Mar 5, 2026
@rustbot
Copy link
Collaborator

rustbot commented Mar 5, 2026

r? @Jarcho

rustbot has assigned @Jarcho.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: 7 candidates
  • 7 candidates expanded to 7 candidates
  • Random selection from Jarcho, dswij, llogiq, samueltardieu

Comment on lines +14 to +18
const FEATURE_SLICE_AS_MUT_ARRAY: RustcVersion = RustcVersion {
major: 1,
minor: 93,
patch: 0,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be defined in clippy_utils::msrvs.

}

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) {
if let ExprKind::MethodCall(_, recv_expr, _, try_into_span) = expr.kind
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was already done before calling this. Just pass the arguments you need in.

Comment on lines +85 to +91
fn receiver(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<TryIntoReceiver> {
match cx.typeck_results().expr_ty(expr).kind() {
ty::Slice(_) => Some(TryIntoReceiver::Slice),
ty::Ref(_, ref_ty, Mutability::Mut) if let ty::Slice(_) = ref_ty.kind() => Some(TryIntoReceiver::SliceMutRef),
_ => None,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be better as a method of TryIntoReceiver. Should also take Ty rather than hiding the access to typeck behind a function.

Comment on lines +28 to +32
// try_into is called with slice or slice mut ref
&& let Some(receiver) = receiver(cx, recv_expr)

// try_into returns Result<[T; N], TryFromSliceError>
&& let ty::Adt(r_def, args) = cx.typeck_results().expr_ty(expr).kind()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once you know you're calling TryInto::try_into You can get the source and destination types using node_args.

&& let [src_ty, dst_ty] = &**cx.typeck_result().node_args(call_expr.hir_id)

This will also mean you don't have to deal with Result at all.

Comment on lines +39 to +45
&& let Some(parent_call) = get_parent_expr(cx, expr)
&& let ExprKind::MethodCall(path, .., unwrap) = parent_call.kind
&& let sym::unwrap | sym::expect = path.ident.name

// use mut ref
&& let Some(mut_ref_expr) = get_parent_expr(cx, parent_call)
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, inner_expr) = mut_ref_expr.kind
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When walking multiple parents you should use TyCtxt::hir_parent_iter.

Comment on lines +56 to +76
(
mut_ref_expr.span.with_hi(try_into_span.hi()),
format!("{recv_snippet}.as_mut_array()"),
)
} else {
(
mut_ref_expr.span.with_hi(recv_expr.span.hi()),
match receiver {
TryIntoReceiver::Slice => format!(
"({mut_ref_snippet} {recv_snippet})",
mut_ref_snippet = snippet(
cx,
mut_ref_expr
.span
.until(inner_expr.span.with_leading_whitespace(cx).into_span()),
".."
)
),
TryIntoReceiver::SliceMutRef => recv_snippet.to_string(),
},
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't work if the expression has extra parenthesis. e.g. &mut (x.try_into().unwrap()). Trying to minimize the suggestion size is quite a bit of work and I don't recommend doing it with the current snippet and span APIs. Just replace the whole expression.

)
};

diag.span_suggestion(span, "try", sugg, Applicability::MachineApplicable);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a MachineApplicable suggestion since it's a semantic change. The help message should also be something like "to borrow the slice as an array" so it's clear what's being recommended.

A second suggestion for something like <[_; _]>::try_from() when creating a new array is actually the intention would also be nice. It's nicer than having to add an expect to silence the lint.

mut_ref_expr.span.with_hi(unwrap.hi()),
"using a mutable reference to temporary array",
|diag| {
let recv_snippet = snippet(cx, recv_expr.span, "..");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use snippet_with_context.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Mar 6, 2026
@rustbot
Copy link
Collaborator

rustbot commented Mar 6, 2026

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@Jarcho
Copy link
Contributor

Jarcho commented Mar 8, 2026

@rustbot label lint-nominated

@rustbot rustbot added the lint-nominated Create an FCP-thread on Zulip for this PR label Mar 8, 2026
@rustbot
Copy link
Collaborator

rustbot commented Mar 8, 2026

This lint has been nominated for inclusion.

A FCP topic has been created on Zulip.

@faeroon
Copy link
Author

faeroon commented Mar 9, 2026

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties and removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lint-nominated Create an FCP-thread on Zulip for this PR needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-review Status: Awaiting review from the assignee but also interested parties

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lint suggestion: the &mut [T; N] creation pitfall

3 participants