Skip to content

Commit e097fd1

Browse files
committed
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`.
1 parent 449c801 commit e097fd1

File tree

1 file changed

+71
-1
lines changed

1 file changed

+71
-1
lines changed

src/doc/rustc/src/lints/levels.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,4 +330,74 @@ $
330330
331331
This feature is used heavily by Cargo; it will pass `--cap-lints allow` when
332332
compiling your dependencies, so that if they have any warnings, they do not
333-
pollute the output of your build.
333+
pollute the output of your build. However, note that `--cap-lints allow` does **not** override lints marked as `force-warn`.
334+
335+
## Priority of Lint Level Sources
336+
337+
Rust allows setting lint levels (`allow`, `warn`, `deny`, etc.) through various sources:
338+
339+
- Attributes (`#[allow(...)]`, `#![deny(...)]`, etc.)
340+
- Command-line options (e.g., `--cap-lints`, `-A unused_variables`)
341+
342+
When multiple lint levels apply to the same lint, the compiler resolves conflicts based on the **source’s scope and strength**.
343+
344+
### Priority of sources (`allow`, `warn`, and `deny`)
345+
346+
For standard lint levels, **the most specific scope** takes precedence.
347+
348+
For example, the following allows the `unused-variables` lint, because it has a more specific scope:
349+
350+
```rust
351+
#![deny(unused_variables)]
352+
353+
#[allow(unused_variables)]
354+
fn main() {
355+
let x = 42; // Allow wins
356+
}
357+
```
358+
359+
### Priority of sources (`force-warn`and `forbid`)
360+
361+
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:
362+
363+
Special lint levels take precedence over standard levels. When multiple special levels are in effect, **the least specific (outermost) scope** takes precedence.
364+
365+
For example, consider the following code:
366+
367+
```rust,compile_fail
368+
#[forbid(unused_variables)]
369+
fn main() {
370+
let x = 42; // Allow wins
371+
}
372+
```
373+
374+
If we compile it with `--force-warn unused_variables` as:
375+
376+
```bash
377+
$ rustc --force-warn unused_variables lib.rs
378+
warning: unused variable: `x`
379+
--> lib.rs:3:9
380+
|
381+
40 | let x = 42;
382+
| ^ help: if this is intentional, prefix it with an underscore: `_x`
383+
|
384+
= note: requested on the command line with `--force-warn unused-variables`
385+
386+
warning: 1 warning emitted
387+
```
388+
389+
`force-warn`/`forbid` take precedence over other lint levels regardless.
390+
391+
General rule of thumb for allow deny and warn in the AST-hierarchy whoever has the most-specific scope takes precedence.
392+
393+
General rule of thumb for force-warn forbid in the AST-hierarchy whoever has the least-specific scope takes precedence.
394+
395+
--cap-lint=allow can not revert --force-warn but it can revert forbid regardless of position.
396+
397+
force-warn / forbid take precedence over deny, allow, and warn regardless.
398+
399+
### Special case priorities
400+
401+
- `forbid` takes precendece over other lint configurations in case of multiple, except for --cap-lint
402+
403+
The special levels `forbid` and `force_warn` take precedence over **regardless of where they are set**.

0 commit comments

Comments
 (0)