Skip to content

perf: skip redundant clone analysis for clone-free functions - #17486

Open
charliermarsh wants to merge 2 commits into
rust-lang:masterfrom
charliermarsh:charlie/clippy-redundant-clone-prefilter
Open

perf: skip redundant clone analysis for clone-free functions#17486
charliermarsh wants to merge 2 commits into
rust-lang:masterfrom
charliermarsh:charlie/clippy-redundant-clone-prefilter

Conversation

@charliermarsh

Copy link
Copy Markdown

On master, redundant_clone requests optimized MIR for every function. It turns out this is fairly expensive. This PR adds a pre-filter that scans each function’s HIR first and skips MIR analysis unless the body contains a .clone(), .to_owned(), .to_string(), .to_path_buf(), or .to_os_string() call. (It's just a pre-filter so false positives are acceptable.)

Benchmarking on my M4, incremental Clippy checks in codex-rs went from 4.19 s to 3.98 s (~5% improvement). A more contrived workload (4,096 functions) went from 220 ms to 178 ms (~19% improvement).

changelog: none

Scan function bodies for clone-like method calls before requesting
optimized MIR. Skip nested closures because they receive their own lint
callbacks, and preserve qualified-call, alias, macro, and closure coverage.

On Rust 1.95, the synthetic 4,096-function workload improved from
220 ms to 178 ms. Codex incremental core checks improved from 4.19 s
to 3.98 s at the median.
@rustbot

rustbot commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome!

You should hear from one of our reviewers after this PR gets at least 2 reviews from the community.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot rustbot added S-waiting-on-community-reviews Status: This is awaiting for positive reviews from the community before a maintainer is assigned. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Aug 1, 2026

@CommanderStorm CommanderStorm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

community review: LGTM
I have one question if you prefer another way of writng this, feel free to reject

View changes since this review

Comment on lines +255 to +268
fn contains_clone_like_call(body: &Body<'_>) -> bool {
for_each_expr_without_closures(body, |expr| {
if let ExprKind::MethodCall(method, ..) = expr.kind
&& matches!(
method.ident.name,
sym::clone | sym::to_owned | sym::to_string | sym::to_path_buf | sym::to_os_string
)
{
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
})
.is_some()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

see above

Suggested change
fn contains_clone_like_call(body: &Body<'_>) -> bool {
for_each_expr_without_closures(body, |expr| {
if let ExprKind::MethodCall(method, ..) = expr.kind
&& matches!(
method.ident.name,
sym::clone | sym::to_owned | sym::to_string | sym::to_path_buf | sym::to_os_string
)
{
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
})
.is_some()
fn contains_no_clone_like_call(body: &Body<'_>) -> bool {
for_each_expr_without_closures(body, |expr| {
if let ExprKind::MethodCall(method, ..) = expr.kind
&& matches!(
method.ident.name,
sym::clone | sym::to_owned | sym::to_string | sym::to_path_buf | sym::to_os_string
)
{
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
})
.is_none()

Comment on lines +78 to +80
// Closures receive their own `check_fn` callback and are checked separately.
// Building MIR for `fn`s with unsatisfiable clauses results in ICE.
if fn_has_unsatisfiable_clauses(cx, def_id.to_def_id()) {
if !contains_clone_like_call(body) || fn_has_unsatisfiable_clauses(cx, def_id.to_def_id()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤔 would this be cleaner?

(lol on the diff github produces)

Suggested change
// Closures receive their own `check_fn` callback and are checked separately.
// Building MIR for `fn`s with unsatisfiable clauses results in ICE.
if fn_has_unsatisfiable_clauses(cx, def_id.to_def_id()) {
if !contains_clone_like_call(body) || fn_has_unsatisfiable_clauses(cx, def_id.to_def_id()) {
// Closures receive their own `check_fn` callback and are checked separately.
// Building MIR for `fn`s with unsatisfiable clauses results in ICE and is expensive.
if contains_no_clone_like_call(body) || fn_has_unsatisfiable_clauses(cx, def_id.to_def_id()) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-community-reviews Status: This is awaiting for positive reviews from the community before a maintainer is assigned. 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.

3 participants