error: unused variable: `x` when lint set to deny in Cargo.toml
0 reputation · 01 Nov 2025, 21:37 UTC
0 reputation · 01 Nov 2025, 21:37 UTC
Goal: configure Rust compiler lints so that useful alerts about unused variables and other code quality issues are visible, while reducing irrelevant noise that can hide genuine problems.
Constraints: deciding which lints to promote to error level, which to keep as warnings, and how to apply temporary overrides via cargo clippy flags or RUSTFLAGS without affecting external crates or causing instability on older toolchains where certain lints may not exist.
What combination of lint levels in Cargo.toml and clippy flags provides actionable alerts for unused variables without silencing other useful warnings?
Which approach scopes temporary lint adjustments to the current crate only, ensuring dependencies retain their default lint behavior?
Which strategy prevents inadvertently promoting unstable lints to forbid, which could break builds on older Rust releases?
35275 reputation · 01 Nov 2025, 21:50 UTC
The error is appearing because unused_variables — normally a warning — has been promoted to deny, so rustc aborts the build on let x = ...; that is never read. The fix is not to remove the lint, but to scope it correctly: keep unused_variables at deny (or warn) for your crate only, leave everything else at default levels, and use -D/-W flags — never -F — for temporary overrides.
The [lints] table in Cargo.toml (supported since Rust 1.74) is the cleanest way to make this durable and scoped to your crate:
[lints.rust]
unused_variables = "deny"
dead_code = "warn"Lints configured this way apply only when compiling your crate. Dependencies are built with their own lint configuration, so a dependency that intentionally leaves a variable unused will still compile. The older equivalent — #![deny(unused_variables)] at the top of src/main.rs or src/lib.rs — behaves the same way and works on older toolchains.
Everything you do not list keeps its default level, so dead_code, unused_imports, and the rest still surface as warnings. That is how you keep the signal without silencing other diagnostics.
For one-off strictness — for example in CI or while cleaning up a module — forward the flag to rustc:
cargo clippy -- -D unused-variables
cargo clippy -- -W clippy::pedantic -D unused-variablesThe -- separator matters: everything after it goes to rustc, not to cargo. This changes nothing in your source or Cargo.toml, so the override lasts only for that invocation. Because it applies to your crate's compilation (dependencies were already built with their own settings), it stays scoped to your code. Note that unused_variables is a rustc lint, not a Clippy lint, which is why it works through this forwarding mechanism.
forbid (-F) cannot be overridden anywhere in the crate, and promoting an unknown or renamed lint to a hard level is what breaks builds on toolchains where that lint does not exist. deny still produces an error but can be locally relaxed with #[allow(unused_variables)] on a specific item — useful for intentional cases like trait implementations or feature-gated code:
#[allow(unused_variables)]
fn handler(x: Request) { /* x used only under cfg(feature = "logging") */ }rustc --version
rustc -W help | grep unused-variablesThe lint name is stable and long-established, but confirm it exists on the oldest toolchain in your support matrix before committing the [lints] table. One caveat worth checking: the [lints] manifest table itself requires Cargo 1.74+; on older toolchains the table is ignored (or errors, depending on version), so use the crate-root attribute form there. If your crate is a published library, consider warn instead of deny — a hard error in a library can frustrate downstream builds that hit edge cases you did not.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.