Skip to content

perf: fold all early lint passes into one statically-combined pass#17132

Merged
llogiq merged 1 commit into
rust-lang:masterfrom
xmakro:perf/combine-early-passes
Jun 2, 2026
Merged

perf: fold all early lint passes into one statically-combined pass#17132
llogiq merged 1 commit into
rust-lang:masterfrom
xmakro:perf/combine-early-passes

Conversation

@xmakro
Copy link
Copy Markdown
Contributor

@xmakro xmakro commented Jun 1, 2026

Clippy registers about 50 early passes, each as its own boxed dyn EarlyLintPass. Every check_* call is an indirect (vtable) dispatch, even for the many passes that don't override that method and just run the empty default. Walking the AST multiplies this across every node.

This folds all early passes into a single statically-combined struct: one concrete field per pass, with a single EarlyLintPass impl that forwards each check_* to every field in turn. Because the field types are concrete and the calls are #[inline(always)], passes that don't override a method contribute a DCE'd empty body and the ones that do become direct, inlined calls. No vtable and no per-node dynamic dispatch.

This mirrors the late-pass combine from #17124, but with no Gated active flag. rustc drops fully-disabled late passes via lints_that_dont_need_to_run, but the early pass runner has no such filtering. The EarlyLintPass impl is generated from rustc's early_lint_methods! list so the two cannot drift.

cargo dev new_lint now emits a combined-struct field for new early passes at the in-list marker.

Measured the same way as #17124 (valgrind callgrind, release build, this branch against its parent, re-linting the ripgrep 14.1.0 workspace): clippy-driver instructions drop about 3.9%, from 1317445596 to 1266296487. The improvement is smaller than the late-pass combine because there are far fewer early passes and the AST walk is lighter than the HIR walk. The UI test suite and dogfood pass unchanged.

changelog: none

@xmakro xmakro force-pushed the perf/combine-early-passes branch from 3eeec14 to 6884673 Compare June 1, 2026 15:26
@xmakro xmakro marked this pull request as ready for review June 1, 2026 15:29
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jun 1, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 1, 2026

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @llogiq (or someone else) some time within the next two weeks.

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
Why was this reviewer chosen?

The reviewer was selected based on:

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

@rustbot

This comment has been minimized.

@xmakro
Copy link
Copy Markdown
Contributor Author

xmakro commented Jun 1, 2026

cc @blyxyas who reviewed related #17124

@xmakro xmakro force-pushed the perf/combine-early-passes branch from 6884673 to 666e75b Compare June 1, 2026 15:34
@xmakro
Copy link
Copy Markdown
Contributor Author

xmakro commented Jun 1, 2026

⚠️ Warning ⚠️

  • There are issue links (such as #123) in the commit messages of the following commits.
    Please move them to the PR description, to avoid spamming the issues with references to the commit, and so this bot can automatically canonicalize them to avoid issues with subtree.

Resolved

Clippy registers about 50 early passes, each as its own boxed
`dyn EarlyLintPass`. Every `check_*` call is an indirect (vtable) dispatch,
even for the many passes that don't override that method and just run the
empty default. Walking the AST multiplies this across every node.

Fold all early passes into a single statically-combined struct: one concrete
field per pass, with a single `EarlyLintPass` impl that forwards each
`check_*` to every field in turn. Because the field types are concrete and the
calls are `#[inline(always)]`, passes that don't override a method contribute a
DCE'd empty body and the ones that do become direct, inlined calls. No vtable
and no per-node dynamic dispatch.

changelog: none
@xmakro xmakro force-pushed the perf/combine-early-passes branch from 666e75b to d5c0121 Compare June 1, 2026 15:35
@samueltardieu
Copy link
Copy Markdown
Member

r? blyxyas
@rustbot label G-performance-project

@rustbot rustbot assigned blyxyas and unassigned llogiq Jun 1, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 1, 2026

blyxyas is not on the review rotation at the moment.
They may take a while to respond.

@rustbot rustbot added the G-performance-project Goal: For issues and PRs related to the Clippy Performance Project label Jun 1, 2026
@llogiq llogiq added this pull request to the merge queue Jun 2, 2026
Merged via the queue into rust-lang:master with commit 6d336d5 Jun 2, 2026
11 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

G-performance-project Goal: For issues and PRs related to the Clippy Performance Project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants