Clippy adds every lint to at least one group which makes it easy to blanket allow/deny/expect/forbid/warn lints and override lints as you see fit. I realize this can be problematic, so Clippy has the warn-by-default blanket_clippy_restriction_lints lint.
Could rustc do something similar? As of rustc 1.93.0, there are are 37 allow-by-default lints and 27 deny-by-default lints that are not part of any group per the output of rustc -Whelp. I finally got tired of manually updating my [lints.rust] table in Cargo.toml when I upgrade rustc, that I hacked up a program that does it for me. This has a few problems:
Unless I publish to crates.io, it doesn't help others.
One has to robustly or conservatively parse the output of rustc -Whelp which has problems: the former is more susceptible to false positives and negatives while the latter (which I chose) is more susceptible to breakage seeing how rustc -Whelp doesn't have some stabilized format.
Even if correct, every update to rustc will cause [lints.rust] to be possibly out-of-date until the program is run again. While this would be true even if every lint were added to at least one group, new/removed groups would obviously be less frequent.
rustc could add a similar warn-by-default lint as blanket_clippy_restriction_lints that fires when one denys/forbids a group of lints one likely shouldn't in addition to a warn-by-default lint that fires when one allows/expects a group of lints that likely should retain their deny-by-default status.
Should be noted that there is already overlap among groups including some groups that are a subset of the union of other groups (e.g., keyword-idents is a proper subset of the union of rust-2018-compatibility and rust-2024-compatibility), so I think even an allowed and denied group would be a quick and dirty solution—unstable lints (e.g., fuzzy-provenance-casts) should probably have their own unstable group though.
What do you see as the benefit of putting lints in at least one group? It sounds like you want to make sure your [lints.rust] affects all lints, but why do you want to do that?
The same reason Clippy has added all lints to at least one group. It's not a coincidence that there aren't any Clippy lints that are groupless. It is not ideal that one must read about any new lints that are added to enjoy their benefit. By using groups, one can benefit from a lint they didn't know existed. For example, trivial-casts is something I likely wouldn't have known about if it weren't for my "obsession" of staying on top of the lints; and it has found cases where I could remove such casts. As stated above, I realize that grouping all lints doesn't prevent the possibility of someone not benefiting from a new lint they didn't know about due to a new group; but mathematically new groups would be less likely.
What benefit is there to having lints that are not grouped? If you want to maintain the status quo, then just don't use these new groups.
One benefit is that it stops people from enabling new lints that are intentionally allow-by-default because they don't work well enough yet just because they decided that they wanted to turn everything on.
warn(clippy::pedantic) is, IMHO, an anti-pattern but that doesn't stop people from thinking it's a good idea.
To me, the right thing is having some new lint groups, like the one that's been talked about a bunch to add a "I'm a high-usage library who wants to be extra careful about semver so want nitpicks about things that don't matter to most code" group.
But I see no reason to say that everything has to be in a group. Especially given rustc's much higher bar for lints in general: if something is warn-by-default, why would it need to be in another group too?
Wouldn't that be covered by the blanket_clippy_restriction_lints analog?
deny(clippy::pedantic) has saved me, and I accept the consequences of keeping my libraries up-to-date when a new lint is added I don't want. Similarly, for binaries I go even further than the typical justification of not denying groups of lints by allowing everything including the deny-by-default lints before publishing to crates.io since it's expected for end users to install such crates, and I don't want such builds to fail or even warn them unlike library-only crates which only affects developers since cargo downgrades deny to warn for dependencies.
It doesn't since such a lint is already in a group: warnings. At most you seem to be against an allowed group, but why isn't there a denied group? I'm guessing it's because you're worried people will similarly "abuse" such a group by allowing/expecting it when they should keep it enabled, but again that's where a blanket_clippy_restriction_lints analog would help.
I already answered that question. When I'm developing code, I deny everything and individually allow/expect lints I don't want to use since I don't subscribe to the "anti-pattern" belief you do. I've found bugs that I wouldn't have if I didn't globally deny even problematic lint groups. For library-only packages this never changes. For packages with at least one binary crate though, I allow everything right before publishing to crates.io for the same reason people object to denying too many lints (e.g., clippy::nursery and clippy::restriction): I don't want builds to suddenly start breaking or annoying end users with warnings. I would never globally allow all deny-by-default lints during development.
I'll also add that unlike the dozen or so Clippy lints that I allow after denying the groups they are in, I have yet to allow any of theallow-by-default lints that are not in a group illustrating to me that globally denying such lints isn't nearly as annoying or problematic as some of the Clippy lints. I can have a higher tolerance for things though, so there certainly would be developers that would re-allow some of the lints (e.g., unused-results).
That doesn't solve the problem though since I'd still have to maintain the curated list of lints without groups. The problem is not about what to do when a lint is triggered (e.g., deny), it's about applying a specific action (e.g., warn) to all lints. If every lint were part of at least one group, the problem is reduced to simply specifying the lint groups and their corresponding action and priority. While yes rustc could always add/remove lint groups, that would statistically be less frequent than individual lints.
Excluding renamed lints, there are 63 allowed-by-default lints in rustc. Of these 23 are exclusively for edition migrations and should not be enabled outside of it (or would never trigger if you have already upgraded to the respective edition), 9 are only usable or relevant on nightly (unstable lints and the unstable_features lint), leaving just 31 lints you may want to enable at all. A bunch of these are allowed-by-default because they have known false-positives and a bunch are restrictions that only make sense to enable individually on a project-by-project basis. For completeness the list of 31 lints I am referring to is:
That doesn't change my stance. I accept false positives and negatives; and as stated, I have yet to allow any of them on a global level because I'm not affected by such a thing. If this doesn't happen, then so be it and I'll continue to use the program I wrote that generates them all.
Is that rustc 1.93.0? If so, then rustc -Whelp is missing 3 of them that would be nice for it to output. The 60 lints that are reported from rustc -Whelp as allow-by-default are the following:
absolute-paths-not-starting-with-crate
ambiguous-negative-literals
closure-returning-async-block
deprecated-in-future
deprecated-safe-2024
deref-into-dyn-supertrait
edition-2024-expr-fragment-specifier
elided-lifetimes-in-paths
explicit-outlives-requirements
ffi-unwind-calls
fuzzy-provenance-casts*
if-let-rescope
impl-trait-overcaptures
impl-trait-redundant-captures
keyword-idents-2018
keyword-idents-2024
let-underscore-drop
linker-messages
lossy-provenance-casts*
macro-use-extern-crate
meta-variable-misuse
missing-copy-implementations
missing-debug-implementations
missing-docs
missing-unsafe-on-extern
multiple-supertrait-upcastable*
must-not-suspend*
non-ascii-idents
non-exhaustive-omitted-patterns*
redundant-imports
redundant-lifetimes
resolving-to-items-shadowing-supertrait-items*
rust-2021-incompatible-closure-captures
rust-2021-incompatible-or-patterns
rust-2021-prefixes-incompatible-syntax
rust-2021-prelude-collisions
rust-2024-guarded-string-incompatible-syntax
rust-2024-incompatible-pat
rust-2024-prelude-collisions
shadowing-supertrait-items*
single-use-lifetimes
tail-expr-drop-order
trivial-casts
trivial-numeric-casts
unit-bindings
unnameable-types
unqualified-local-imports*
unreachable-pub
unsafe-attr-outside-unsafe
unsafe-code
unsafe-op-in-unsafe-fn
unstable-features
unused-crate-dependencies
unused-extern-crates
unused-import-braces
unused-lifetimes
unused-macro-rules
unused-qualifications
unused-results
variant-size-differences
What are the 3 other lints you are finding, and why isn't rustc -Whelp outputting them? If you wouldn't mind at least reporting the 63 lints you found, I can figure out which ones are missing myself.
The following 37 of those 60 are not part of a group:
I used the list at Allowed-by-default Lints - The rustc book There seems to be some divergence. For example it lists async-idents which you don't have, while you have deprecated-in-future, which is not listed there.
Ah, yeah I stopped using that list since I think rustc -Whelp is more accurate and I wanted something I could use programmatically to overcome what I consider a limitation. For what it's worth, async-idents has been renamed to keyword-idents-2018.
If you don't mind my asking, why wouldn't you publish said tool (assuming it already exists, which my understanding is that it does)? I follow a similar practice of enabling quite a lot of lints and allow-ing them when I decide they are not appropriate, and it would be nice to have a tool making it easier to know when new lints are available (or when they get renamed, which recently caused some confusion for me).
On another note, when a lint is added/changed, are you updating all of your projects manually? If so, if they're similar enough to benefit from roughly the same lints, you could consider using a common base for your projects. You can update the lints there, and then you just need to rebase (I'm assuming you are using git, but I'd think you could achieve something similar with any version control system... which I am also assuming you are using).
I write a lot of stuff just for me, and I feel it'd be "inappropriate" for me to release it to others if I haven't taken the proper amount of time and care. I recently just hacked something up not really thinking about "others".
I went ahead and took some time to make it "good enough" that others may find it useful, so here you go.
The output of rustc -Whelp is pretty basic, and you can likely just rely on your favorite regex app (e.g., ripgrep) to parse the lints out for you. You'll still have to rely on systemd.timer(5), cron(8), or whatever other tool you want to schedule some automatic process to execute the necessary command(s). Currently I run rustup update and lints everyday; and in the event there is a difference between the output of lints and the current file I have, I get an e-mail sent notifying me that I need to update things.
Currently I do update everything manually after being notified by cron(8), but I may change that.