S25: #[allow(...)] to silence warnings
What it looks like
Section titled “What it looks like”#[allow(unused_variables)]pub fn apply_discount(total_cents: u64, percent: u64) -> u64 { total_cents // the warning said that `percent` is never used. It was right.}
#[allow(unused_must_use)]pub fn save_report(path: &Path, report: &str) { fs::write(path, report); // a failed write is now silent}
#[allow(clippy::cast_possible_truncation)]pub fn quantity(input: u64) -> u16 { input as u16 // 70_000 becomes 4_464}Each #[allow(...)] hides a real bug:
unused_variables: the discount is never applied. The function returns the full price.unused_must_use: a failed write is ignored. See S08: IgnoredResult(let _ =,.ok();).clippy::cast_possible_truncation:70_000 as u16is4_464, with no error.
The test worse_hides_real_bugs shows all three.
Why AI agents produce it
Section titled “Why AI agents produce it”- The task says “fix the warnings”. An
#[allow]makes the warning go away in one line, and the agent counts that as done. - The compiler output suggests it. Every Clippy warning ends with “to override … add
#[allow(...)]”. An agent that reads the last line takes it. - It is common in training data. Many projects have
#[allow(dead_code)]at the top of a file, often for good reasons during early development. - The real fix is larger. Using
percentcorrectly, or returning aResult, changes the function signature and its callers. The#[allow]changes nothing else.
Why it is a problem
Section titled “Why it is a problem”- The warning was right. Rust warnings and the default Clippy lints have few false positives. A hidden warning is usually a hidden bug.
- It stays forever. If the code changes so that the warning no longer applies,
#[allow]says nothing. It keeps silencing the lint for any new code in the same item. - It gives no reason. The reviewer cannot tell a considered exception from a shortcut.
- On a module or crate,
#![allow(...)]turns a lint off for all the code below it, also for code written later.
The better version
Section titled “The better version”WorseThree
#[allow]attributes. Each one hides a bug.#[allow(unused_variables)]pub fn apply_discount(total_cents: u64, percent: u64) -> u64 {total_cents // the warning said that `percent` is never used. It was right.}#[allow(unused_must_use)]pub fn save_report(path: &Path, report: &str) {fs::write(path, report); // a failed write is now silent}#[allow(clippy::cast_possible_truncation)]pub fn quantity(input: u64) -> u16 {input as u16 // 70_000 becomes 4_464}BetterThe discount is applied, the write error is returned, and
u16::try_fromrejects a value that does not fit.pub fn apply_discount(total_cents: u64, percent: u64) -> u64 {total_cents - total_cents * percent.min(100) / 100}pub fn save_report(path: &Path, report: &str) -> io::Result<()> {fs::write(path, report)}pub fn quantity(input: u64) -> Result<u16, TryFromIntError> {u16::try_from(input)}
Fix the code that the warning describes. The fix is often a type change: -> io::Result<()> instead of (), or try_from instead of as. The test better_fixes_them checks each fix.
When it is acceptable
Section titled “When it is acceptable”Sometimes the lint is wrong for this code. Then use #[expect(...)] with a reason:
/// The percentage of paid orders, from 0 to 100.#[expect( clippy::cast_possible_truncation, reason = "the percentage is at most 100, so it fits in a u8")]pub fn paid_percent(paid: u64, total: u64) -> u8 { if total == 0 { return 0; } (paid.min(total) * 100 / total) as u8}#[expect]instead of#[allow](stable since Rust 1.81). If the lint stops firing, the compiler warns that the expectation is unfulfilled, so the attribute cannot outlive its reason.reason = "..."says why the lint does not apply. Here the code makes sure that the value is at most 100.- On the smallest item: one function or one statement, not the module.
- Generated code, FFI bindings, and test helpers often have module-level allows with a comment. That is normal.
How to detect it
Section titled “How to detect it”- Search the diff for
allow(. Every new one needs a reason. - Clippy
allow_attributes(restriction group) reports every#[allow]and suggests#[expect].allow_attributes_without_reason(restriction group) reports an#[allow]or#[expect]with noreason. Both are off by default. Turn them on in[lints.clippy]ofCargo.toml. - Look at
[lints]inCargo.tomltoo. A lint set to"allow"there turns it off for the whole crate.
What to tell your agent
Section titled “What to tell your agent”Do not add #[allow(...)] to make a warning go away. Fix the code that thewarning describes. If the lint is wrong for one specific item, use#[expect(lint_name, reason = "...")] on that item only, and explain in thereason why the lint does not apply. Remove any #[allow] you added in thischange, then run cargo clippy --all-targets -- -D warnings and the tests.Related: S08: Ignored Result (let _ =, .ok();), S02: unwrap() / expect() in non-test code, and Tooling.