I had an idea to make the #[expect(lint)]
attribute being worked on in that issue more useful, and the RFCs repo suggested I make a post here for feedback before writing an RFC, so I'm following that. Sorry if I do anything wrong, I'm new to contributing to Rust.
Quick summary of #[expect(lint)]
attribute: It's like allow
, but if no instances of the underlying lint exist in the region covered by this attribute, then it raises a warning (see the tracking issue for more details/discussion around edge cases).
For my code, this attribute would be useful to include allowances for lints of a limited scope with intention to remove them eventually from the code, and expect
producing a warning is a great signal to the programmer that the allowance is no longer needed and can be removed. Obviously, it is preferable to limit the scope of the allowance to only the offending code, so no such addition is possible, but this is only sometimes possible (e.g. no way to put an allow
on the body of a derive
impl).
However, this approach has a drawback: new code can be written in the same region as existing exceptions that adds new exceptions to the lint, and the allowance means this won't be discovered.
To ameliorate this drawback, I propose extending the attribute by allowing #[expect(lint, count = N)]
(count = N
being optional), which will raise a warning if there aren't exactly N
instances of the offending lint in the region covered by the expect
attribute, and it will only suppress the internal lints if there are exactly the right amount (I'm flexible on this last part, but imo it'll be easier to use if you see all != N
lints so you know what changed).
For an example, to slightly modify the original RFC that proposed the #[expect(lint)]
attribute:
#[expect(unused_mut, count = 1)]
fn no_lints() -> usize {
let mut a = Vec::new();
a.len()
}
#[expect(unused_mut, count = 1)]
fn lints() -> usize {
let mut a = Vec::new();
// New code was added that also triggers `unused_mut`
let mut b = Vec::new();
a.len()
}
The no_lints
function would compile without any lints, since there is one instance of unused_mut
that would have triggered without the expect
being in place. On the other hand, lints
would produce three lints: one for each of the unused_mut
triggers(a
and b
), and a lint on the #[expect(...)]
attribute indicating that there were 2 instances, not 1.
Any thoughts on this?