rustc -D warnings (RUSTFLAGS="-D warnings"): treat warnings as errors
- tool
- Rust
- command
- rustc
- flag
- -D warnings (--deny warnings)
- default
- most lints are warn: warnings are printed and the build succeeds
rustc -D warnings main.rs raises every lint that is currently a warning to an error, so the build fails instead of printing warning: ... emitted and succeeding. In Cargo projects it is usually passed as RUSTFLAGS="-D warnings" cargo build or cargo clippy -- -D warnings, typically in CI. -D is short for --deny; the other lint levels are -A (allow), -W (warn), --force-warn and -F (forbid).
Without and with -D warnings
cat > w.rs <<'EOF'
fn main() {
let unused = 5;
let mut n = 1;
println!("{}", 2);
}
EOF
echo "== default"
rustc w.rs 2>&1 | grep -E "^(warning: unused|warning: variable|warning: [0-9])"; echo "exit: ${PIPESTATUS[0]}"
echo "== -D warnings"
rustc -D warnings w.rs 2>&1 | sed -n '1,9p'; echo "exit: ${PIPESTATUS[0]}"
echo "== -D warnings -A unused-mut -A unused-variables"
rustc -D warnings -A unused-mut -A unused-variables w.rs; echo "exit: $?"
echo "== -A before -D warnings"
rustc -A unused-mut -A unused-variables -D warnings w.rs; echo "exit: $?"Output
== default warning: variable does not need to be mutable warning: unused variable: `unused` warning: unused variable: `n` warning: 3 warnings emitted exit: 0 == -D warnings error: variable does not need to be mutable --> w.rs:3:9 | 3 | let mut n = 1; | ----^ | | | help: remove this `mut` | = note: `-D unused-mut` implied by `-D warnings` exit: 1 == -D warnings -A unused-mut -A unused-variables exit: 0 == -A before -D warnings exit: 0
By default rustc prints three warnings and builds the binary (exit 0). With -D warnings the same messages become errors, each with a note saying which lint was denied and how to override it, and the build stops with exit code 1. Allowing specific lints with -A exempts them, whether the -A comes before or after -D warnings: the warnings group only affects lints that would otherwise be reported as warnings.
Lint level flags
| Flag | Long form | Effect |
|---|---|---|
| -A lint | --allow | Do not report the lint |
| -W lint | --warn | Report as a warning |
| --force-warn lint | Report as a warning, even if the code says #[allow] | |
| -D lint | --deny | Report as an error; code may still #[allow] it |
| -F lint | --forbid | Report as an error that the code cannot override |
| --cap-lints LEVEL | Upper limit for every lint; Cargo uses --cap-lints allow for dependencies |
warnings is a special group meaning "everything that would be a warning". You can also name a group such as unused or rust-2018-idioms, or a single lint such as unused-variables (dashes and underscores are equivalent).
In Cargo projects
RUSTFLAGS="-D warnings" cargo build # rustc lints for the whole workspace
cargo clippy --all-targets -- -D warnings # clippy lints as errors too
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps # broken intra-doc links fail the docs buildSince Rust 1.74 a [lints] table in Cargo.toml sets levels per crate without touching RUSTFLAGS:
[lints.rust]
unsafe_code = "forbid"
unused = "deny"
[lints.clippy]
unwrap_used = "warn"Pitfalls
- New compilers add warnings. A pinned
-D warningsin CI can turn a toolchain update into a red build. Pin the toolchain withrust-toolchain.tomlor treat those failures as routine maintenance. - Allowed lints stay allowed:
-D warningsdoes not re-enable lints switched off with-Aor#[allow]. To make a specific lint an error regardless, name it:-D unused-mut. - Only lints are affected. Hard errors such as E0382 borrow of moved value are errors at every level;
-D warningscannot make them warnings and-Acannot hide them. Use rustc --explain for the error codes.
FAQ
Why does RUSTFLAGS="-D warnings" rebuild all dependencies?
RUSTFLAGS is part of the build fingerprint, so changing it invalidates every cached artifact, dependencies included. Warnings in dependencies are capped by Cargo and do not fail the build, but the rebuild still costs time. Keep the same RUSTFLAGS in every CI step, or use the [lints] table, which applies only to your own crates.
How do I allow one lint while denying all warnings?
Add -A lint-name, for example rustc -D warnings -A unused-mut, or put #[allow(unused_mut)] on the item. The example on this page shows that the allowed lint stays allowed whichever order the flags have.
Is -D warnings the same as #![deny(warnings)] in the code?
It has the same effect, but the attribute is part of the source and breaks the build for everyone who compiles the crate with a newer compiler that adds warnings. Prefer the command-line flag in CI.
Sources
- doc.rust-lang.orgdoc.rust-lang.org/rustc/lints/levels.html
- doc.rust-lang.orgdoc.rust-lang.org/rustc/command-line-arguments.html#-d-set-lint-denied
- doc.rust-lang.orgdoc.rust-lang.org/cargo/reference/config.html#buildrustflags
- doc.rust-lang.orgdoc.rust-lang.org/cargo/reference/manifest.html#the-lints-section