Compiler Warnings
Compiler warnings are built-in static analysis diagnostics (called lints) emitted by rustc when code is type-safe and valid to compile, but exhibits potential bugs, unused variables, dead code, or deprecated API calls. Every rustc lint can be configured across four severity levels: allow, expect, warn, and deny (plus forbid).
Lint Severity Levels in `rustc`:
#[allow(lint)] --> Suppresses the lint completely (silent even if fixed!)
#[expect(lint)] --> Suppresses the lint, BUT warns if the lint is no longer triggered!
#[warn(lint)] --> Emits a compiler warning (compilation still succeeds)
#[deny(lint)] --> Emits a hard compiler error (can be overridden in inner scopes)
#[forbid(lint)] --> Emits a hard compiler error (CANNOT be overridden anywhere inside!)
Lint Control Attributes and #[expect(...)]
Introduced in Rust 1.81 and standard in the Rust 2024 edition, #[expect(lint_name)] is strongly preferred over #[allow(lint_name)] for temporary or local lint suppressions. If you refactor code so the suppressed warning no longer occurs, #[allow(...)] stays behind as stale clutter forever, whereas #[expect(...)] emits an unfulfilled_lint_expectations warning reminding you to remove the attribute!
| Attribute | Suppresses Warning? | Warns When Suppression Becomes Obsolete? | Can Inner Item Override It? |
|---|---|---|---|
#[allow(unused)] |
Yes | No | Yes |
#[expect(unused)] |
Yes | Yes (unfulfilled_lint_expectations) |
Yes |
#[warn(unused)] |
No (emits warning) | — | Yes |
#[deny(unused)] |
No (emits error) | — | Yes (with #[allow] or #[expect]) |
#[forbid(unsafe_code)] |
No (emits error) | — | No (locked across all inner items) |
#![forbid(unsafe_code)]
#![warn(unused_qualifications)]
#[expect(dead_code, reason = "reserved for upcoming v2 wire protocol")]
struct V2Header {
version: u8,
flags: u8,
}
/// Marking a return value `#[must_use]` triggers the `unused_must_use` warning
/// if a caller ignores the returned value.
#[must_use = "ignoring a ValidationOutcome drops the validation result without checking it"]
pub fn validate_input(s: &str) -> bool {
!s.trim().is_empty()
}
fn main() {
let ok = validate_input("rust-2024");
println!("Input valid: {ok}");
}
Input valid: true
Essential Built-In rustc Lints
Even without Clippy, rustc includes several high-value lints that are set to allow by default and should be enabled (warn or deny) in production projects:
rustc Lint Name |
Default Level | Why Enable It |
|---|---|---|
unsafe_code |
allow |
Forbids (#![forbid(unsafe_code)]) or flags unsafe blocks in pure safe crates. |
unsafe_op_in_unsafe_fn |
warn in Rust 2024! |
Requires explicit unsafe { ... } blocks inside unsafe fn bodies so unsafe operations stand out clearly. |
missing_debug_implementations |
allow |
Warns if a public struct or enum forgets #[derive(Debug)]. |
missing_docs |
allow |
Warns if any public item lacks /// documentation. |
unreachable_pub |
allow |
Warns when an item is marked pub inside a private module and is not re-exported. |
unused_crate_dependencies |
allow |
Warns about dependencies listed in Cargo.toml that are never imported in the crate. |
unexpected_cfgs |
warn |
Catches typos in #[cfg(feature = "...")] or #[cfg(target_os = "...")] against Cargo.toml. |