#[allow(...)]
#[allow(lint_name)] (and its inner form #![allow(lint_name)]) suppresses compiler or tool warnings for the specified lint(s) within the annotated scope, permitting code that would otherwise trigger a warn or deny diagnostic to compile silently.
Targeted vs. Crate-Wide Lint Suppression
Rather than placing #![allow(dead_code)] or #![allow(unused_variables)] at the top of an entire crate (which hides genuine bugs across all modules), attach #[allow(...)] to the smallest item, statement, or block that requires the exception.
Documenting Suppression Reasons with reason = "..." (Rust 1.81+)
Stabilized in Rust 1.81, all lint control attributes (#[allow], #[expect], #[warn], #[deny], #[forbid]) accept an optional trailing reason = "..." argument that documents why the lint is suppressed and is echoed in compiler diagnostics if the lint level changes:
#[allow(dead_code, reason = "Reserved for v2 wire protocol fields")]
struct WireHeaderV2 {
version: u8,
reserved_flags: u16,
}
#[allow(
non_snake_case,
reason = "Matches external C library struct field naming convention"
)]
struct CMetricPayload {
TotalRequests: u64,
ErrorCount: u32,
}
fn main() {
let payload = CMetricPayload {
TotalRequests: 1000,
ErrorCount: 2,
};
println!(
"TotalRequests = {}, ErrorCount = {}",
payload.TotalRequests, payload.ErrorCount
);
}
TotalRequests = 1000, ErrorCount = 2
Preferring #[expect(lint_name)] Over #[allow(lint_name)]
Also stabilized in Rust 1.81 (RFC 2383), #[expect(lint_name)] suppresses a lint warning just like #[allow(lint_name)], except that if the underlying code is later fixed and no longer triggers lint_name, the compiler emits an unfulfilled_lint_expectations warning telling you that the #[expect(...)] attribute is now stale and can be deleted!
| Attribute | Suppresses Warning When Lint Fires? | Warns When Lint No Longer Fires? | Best Use Case |
|---|---|---|---|
#[allow(lint)] |
Yes | No (stays silently forever even when obsolete) | Generated code, macros, or platform-conditional code (#[cfg]) where the lint only fires on some targets |
#[expect(lint)] |
Yes | Yes (unfulfilled_lint_expectations) |
Hand-written code where you want to know if a future refactor makes the suppression unnecessary |
#[expect(
unused_variables,
reason = "Parameter `context` will be used once telemetry is wired up"
)]
fn handle_event(event_id: u32, context: &str) {
println!("handled event #{event_id}");
}
fn main() {
handle_event(10, "prod");
}
handled event #10