Attributes and Conditional Compilation

#[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