Background
We don't currently run Clippy on rustfmt's own code. The rust-clippy job in integration.yml runs Clippy on a bunch of external crates to check that rustfmt formats them correctly; it's a formatter regression test, not a lint check on us. The only Clippy-related thing in the source is a handful of stray #[allow(clippy::*)].
If you run cargo clippy --all-targets against main today (toolchain nightly-2026-02-19), you get 269 lint hits in 50 different lints, all from Clippy's default groups. Most are warnings nobody ever sees. But src/cargo-fmt/main.rs and src/format-diff/main.rs both have #![deny(warnings)] at the top, so a Clippy warning in either of those crates becomes a compile error, and cargo clippy --all-targets doesn't actually finish cleanly. We have a Clippy gate already; it just happens to cover exactly two files by accident.
Which lints would this enable
"Default" means everything in clippy::all:
| Group |
Default |
What it's about |
clippy::correctness |
deny |
Code that's almost certainly a bug |
clippy::suspicious |
warn |
Probably wrong, occasionally intentional |
clippy::style |
warn |
Idiomatic Rust style |
clippy::complexity |
warn |
Has a simpler equivalent form |
clippy::perf |
warn |
Avoidable performance cost |
The other groups (pedantic, nursery, restriction, cargo) are allow-by-default and would stay off. Individual lints from those can be opted into later if anyone wants.
Lint reference: https://rust-lang.github.io/rust-clippy/master/index.html
What's firing on main today
Run on nightly-2026-02-19. The four lints marked (E) are the ones currently breaking the build (they have at least one site inside cargo-fmt or format-diff and trip #![deny(warnings)]).
50 lints, 269 sites total
| Sites |
Lint |
| 51 |
clippy::bool_assert_comparison (E) |
| 41 |
clippy::unnecessary_map_or |
| 26 |
clippy::borrow_deref_ref |
| 14 |
clippy::needless_borrow |
| 13 |
clippy::explicit_auto_deref |
| 10 |
clippy::too_many_arguments |
| 9 |
clippy::field_reassign_with_default |
| 8 |
clippy::unnecessary_lazy_evaluations |
| 7 |
clippy::wrong_self_convention |
| 6 |
clippy::io_other_error (E) |
| 6 |
clippy::needless_borrows_for_generic_args |
| 6 |
clippy::expect_fun_call |
| 6 |
clippy::to_string_in_format_args |
| 6 |
clippy::arc_with_non_send_sync |
| 5 |
clippy::redundant_field_names |
| 5 |
clippy::unnecessary_unwrap |
| 4 |
clippy::needless_splitn |
| 4 |
clippy::default_constructed_unit_structs |
| 3 |
clippy::redundant_pattern |
| 2 |
clippy::derivable_impls, clippy::useless_conversion, clippy::len_zero, clippy::manual_pattern_char_comparison, clippy::get_first, clippy::while_let_on_iterator, clippy::skip_while_next, clippy::let_unit_value |
| 1 |
clippy::is_digit_ascii_radix, clippy::nonminimal_bool, clippy::needless_return, clippy::enum_variant_names, clippy::write_with_newline, clippy::needless_lifetimes, clippy::manual_inspect, clippy::ptr_arg, clippy::needless_question_mark, clippy::bind_instead_of_map, clippy::redundant_guards, clippy::clone_on_copy, clippy::collapsible_if, clippy::manual_repeat_n, clippy::borrowed_box, clippy::type_complexity, clippy::extra_unused_lifetimes, clippy::assign_op_pattern, clippy::unwrap_or_default, clippy::legacy_numeric_constants, clippy::map_flatten, clippy::non_canonical_partial_ord_impl (E), clippy::into_iter_on_ref (E) |
Suggested next step
Rather than try to agree on the whole list up front, I think the simplest start is one small PR that just lays the plumbing:
- Add a
[workspace.lints.clippy] table to Cargo.toml with all = "allow". Nothing changes in behavior, and the two cargo-fmt / format-diff build failures go away because there's nothing for #![deny(warnings)] to catch anymore.
- Add a
cargo clippy --all-targets -- -D warnings step to CI. Safe to turn on immediately, since at this point nothing warns.
After that, each lint we want to actually enforce is its own small PR: flip one entry in the table from "allow" to "warn" (or "deny") and include the fixes for that lint in the same PR. The Cargo.toml ends up being the canonical record of which lints we've consciously adopted, and we never get a flood of unrelated warnings landing together.
Background
We don't currently run Clippy on rustfmt's own code. The
rust-clippyjob inintegration.ymlruns Clippy on a bunch of external crates to check that rustfmt formats them correctly; it's a formatter regression test, not a lint check on us. The only Clippy-related thing in the source is a handful of stray#[allow(clippy::*)].If you run
cargo clippy --all-targetsagainstmaintoday (toolchainnightly-2026-02-19), you get 269 lint hits in 50 different lints, all from Clippy's default groups. Most are warnings nobody ever sees. Butsrc/cargo-fmt/main.rsandsrc/format-diff/main.rsboth have#![deny(warnings)]at the top, so a Clippy warning in either of those crates becomes a compile error, andcargo clippy --all-targetsdoesn't actually finish cleanly. We have a Clippy gate already; it just happens to cover exactly two files by accident.Which lints would this enable
"Default" means everything in
clippy::all:clippy::correctnessclippy::suspiciousclippy::styleclippy::complexityclippy::perfThe other groups (
pedantic,nursery,restriction,cargo) are allow-by-default and would stay off. Individual lints from those can be opted into later if anyone wants.Lint reference: https://rust-lang.github.io/rust-clippy/master/index.html
What's firing on
maintodayRun on
nightly-2026-02-19. The four lints marked (E) are the ones currently breaking the build (they have at least one site insidecargo-fmtorformat-diffand trip#![deny(warnings)]).50 lints, 269 sites total
clippy::bool_assert_comparison(E)clippy::unnecessary_map_orclippy::borrow_deref_refclippy::needless_borrowclippy::explicit_auto_derefclippy::too_many_argumentsclippy::field_reassign_with_defaultclippy::unnecessary_lazy_evaluationsclippy::wrong_self_conventionclippy::io_other_error(E)clippy::needless_borrows_for_generic_argsclippy::expect_fun_callclippy::to_string_in_format_argsclippy::arc_with_non_send_syncclippy::redundant_field_namesclippy::unnecessary_unwrapclippy::needless_splitnclippy::default_constructed_unit_structsclippy::redundant_patternclippy::derivable_impls,clippy::useless_conversion,clippy::len_zero,clippy::manual_pattern_char_comparison,clippy::get_first,clippy::while_let_on_iterator,clippy::skip_while_next,clippy::let_unit_valueclippy::is_digit_ascii_radix,clippy::nonminimal_bool,clippy::needless_return,clippy::enum_variant_names,clippy::write_with_newline,clippy::needless_lifetimes,clippy::manual_inspect,clippy::ptr_arg,clippy::needless_question_mark,clippy::bind_instead_of_map,clippy::redundant_guards,clippy::clone_on_copy,clippy::collapsible_if,clippy::manual_repeat_n,clippy::borrowed_box,clippy::type_complexity,clippy::extra_unused_lifetimes,clippy::assign_op_pattern,clippy::unwrap_or_default,clippy::legacy_numeric_constants,clippy::map_flatten,clippy::non_canonical_partial_ord_impl(E),clippy::into_iter_on_ref(E)Suggested next step
Rather than try to agree on the whole list up front, I think the simplest start is one small PR that just lays the plumbing:
[workspace.lints.clippy]table toCargo.tomlwithall = "allow". Nothing changes in behavior, and the twocargo-fmt/format-diffbuild failures go away because there's nothing for#![deny(warnings)]to catch anymore.cargo clippy --all-targets -- -D warningsstep to CI. Safe to turn on immediately, since at this point nothing warns.After that, each lint we want to actually enforce is its own small PR: flip one entry in the table from
"allow"to"warn"(or"deny") and include the fixes for that lint in the same PR. The Cargo.toml ends up being the canonical record of which lints we've consciously adopted, and we never get a flood of unrelated warnings landing together.