From e097fd15c05565257122515d0e44b6a8d8c928c2 Mon Sep 17 00:00:00 2001 From: Hamidreza Sanaee Date: Wed, 4 Jun 2025 10:33:31 +0100 Subject: [PATCH] Doc: clarify priority of lint level sources This updates the rustc book to clearly document how conflicting lint configurations are resolved across different sources, including command-line flags, crate-level attributes, in-line attributes, and `--cap-lints`. It also explains the special behavior of `forbid` and `force_warn`. --- src/doc/rustc/src/lints/levels.md | 72 ++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 18e827bd3c987..3f1934522433c 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -330,4 +330,74 @@ $ This feature is used heavily by Cargo; it will pass `--cap-lints allow` when compiling your dependencies, so that if they have any warnings, they do not -pollute the output of your build. +pollute the output of your build. However, note that `--cap-lints allow` does **not** override lints marked as `force-warn`. + +## Priority of Lint Level Sources + +Rust allows setting lint levels (`allow`, `warn`, `deny`, etc.) through various sources: + +- Attributes (`#[allow(...)]`, `#![deny(...)]`, etc.) +- Command-line options (e.g., `--cap-lints`, `-A unused_variables`) + +When multiple lint levels apply to the same lint, the compiler resolves conflicts based on the **source’s scope and strength**. + +### Priority of sources (`allow`, `warn`, and `deny`) + +For standard lint levels, **the most specific scope** takes precedence. + +For example, the following allows the `unused-variables` lint, because it has a more specific scope: + +```rust +#![deny(unused_variables)] + +#[allow(unused_variables)] +fn main() { + let x = 42; // Allow wins +} +``` + +### Priority of sources (`force-warn`and `forbid`) + +Special lint levels take precedence over standard lint levels, and with eachother, **the least specific scope wins** — the further the attribute is to the code, the higher its precedence: + +Special lint levels take precedence over standard levels. When multiple special levels are in effect, **the least specific (outermost) scope** takes precedence. + +For example, consider the following code: + +```rust,compile_fail +#[forbid(unused_variables)] +fn main() { + let x = 42; // Allow wins +} +``` + +If we compile it with `--force-warn unused_variables` as: + +```bash +$ rustc --force-warn unused_variables lib.rs +warning: unused variable: `x` + --> lib.rs:3:9 + | +40 | let x = 42; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | + = note: requested on the command line with `--force-warn unused-variables` + +warning: 1 warning emitted +``` + +`force-warn`/`forbid` take precedence over other lint levels regardless. + +General rule of thumb for allow deny and warn in the AST-hierarchy whoever has the most-specific scope takes precedence. + +General rule of thumb for force-warn forbid in the AST-hierarchy whoever has the least-specific scope takes precedence. + +--cap-lint=allow can not revert --force-warn but it can revert forbid regardless of position. + +force-warn / forbid take precedence over deny, allow, and warn regardless. + +### Special case priorities + +- `forbid` takes precendece over other lint configurations in case of multiple, except for --cap-lint + +The special levels `forbid` and `force_warn` take precedence over **regardless of where they are set**.