Skip to content

Commit 54d581b

Browse files
Add some docs around the lint store
1 parent 51a4a72 commit 54d581b

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- [Coding conventions](./conventions.md)
2424
- [crates.io Dependencies](./crates-io.md)
2525
- [Emitting Errors and other Diagnostics](diagnostics.md)
26+
- [`LintStore`](./diagnostics/lintstore.md)
2627
- [ICE-breaker teams](ice-breaker/about.md)
2728
- [LLVM ICE-breakers](ice-breaker/llvm.md)
2829
- [Part 2: How rustc works](./part-2-intro.md)

src/diagnostics.md

+38-13
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,17 @@ crate.
171171

172172
[builtin]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/index.html
173173

174-
Each lint is defined as a `struct` that implements the `LintPass` `trait`. The
175-
trait implementation allows you to check certain syntactic constructs the
176-
linter walks the source code. You can then choose to emit lints in a very
177-
similar way to compile errors. Finally, you register the lint to actually get
178-
it to be run by the compiler by using the `declare_lint!` macro.
174+
Every lint is implemented via a `struct` that implements the `LintPass` `trait`
175+
(you also implement one of the more specific lint pass traits, either
176+
`EarlyLintPass` or `LateLintPass`). The trait implementation allows you to
177+
check certain syntactic constructs the linter walks the source code. You can
178+
then choose to emit lints in a very similar way to compile errors.
179+
180+
You also declare the metadata of a particular lint via the `declare_lint!`
181+
macro. This includes the name, the default level, a short description, and some
182+
more details.
183+
184+
Note that the lint and the lint pass must be registered with the compiler.
179185

180186
For example, the following lint checks for uses
181187
of `while true { ... }` and suggests using `loop { ... }` instead.
@@ -196,11 +202,15 @@ declare_lint! {
196202
#[derive(Copy, Clone)]
197203
pub struct WhileTrue;
198204
199-
impl LintPass for WhileTrue {
200-
fn get_lints(&self) -> LintArray {
201-
lint_array!(WHILE_TRUE)
202-
}
203-
}
205+
// This declares a lint pass, providing a list of associated lints. The
206+
// compiler currently doesn't use the associated lints directly (e.g., to not
207+
// run the pass or otherwise check that the pass emits the appropriate set of
208+
// lints). However, it's good to be accurate here as it's possible that we're
209+
// going to register the lints via the get_lints method on our lint pass (that
210+
// this macro generates).
211+
impl_lint_pass!(
212+
WhileTrue => [WHILE_TRUE],
213+
);
204214
205215
// LateLintPass has lots of methods. We only override the definition of
206216
// `check_expr` for this lint because that's all we need, but you could
@@ -242,9 +252,24 @@ declare_lint! {
242252
This makes the `ANONYMOUS_PARAMETERS` lint allow-by-default in the 2015 edition
243253
but warn-by-default in the 2018 edition.
244254

245-
Lints that represent an incompatibility (i.e. error) in the upcoming edition
246-
should also be registered as `FutureIncompatibilityLint`s in
247-
[`register_builtins`][rbuiltins] function in [`rustc_lint::lib`][builtin].
255+
A future-incompatible lint should be declared with the `@future_incompatible`
256+
additional "field":
257+
258+
```rust,ignore
259+
declare_lint! {
260+
pub ANONYMOUS_PARAMETERS,
261+
Allow,
262+
"detects anonymous parameters",
263+
@future_incompatible = FutureIncompatibleInfo {
264+
reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
265+
edition: Some(Edition::Edition2018),
266+
};
267+
}
268+
```
269+
270+
If you need a combination of options that's not supported by the
271+
`declare_lint!` macro, you can always define your own static with a type of
272+
`&Lint` but this is currently linted against in the compiler tree.
248273

249274
### Lint Groups
250275

src/diagnostics/lintstore.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# LintStore
2+
3+
This page documents some of the machinery around lint registration and how we
4+
run lints in the compiler.
5+
6+
The `LintStore` is the central piece of infrastructure, around which everything
7+
rotates. It's not available during the early parts of compilation (i.e., before
8+
TyCtxt) in most of the code, as we need to fill it in with all of the lints,
9+
which can only happen after plugin registration.
10+
11+
We store essentially two separate things in the `LintStore`: a list of all known
12+
lints with associated metadata (default lint levels, notably), and the lint
13+
passes. We store constructors for the lint passes rather than the passes
14+
themselves, because lint passes often want to change state to track something
15+
in the code (so their methods take `&mut self`) and we want to avoid needing to
16+
synchronize access to the LintStore.
17+
18+
For the most part, we currently only instantiate each lint pass once, though in
19+
the future we'll likely want more fine-grained linting to better support
20+
incremental compilation. We already have late module passes which are
21+
constructed per-module if the module changes in an incremental session.
22+
23+
## Registration
24+
25+
We must register both every lint and every lint pass into the `LintStore` for
26+
the code to work properly. This often is as simple as calling
27+
`register_lints(PassType::get_lints())` and then `register_late_pass(||
28+
Box::new(PassType))`.
29+
30+
Within the compiler, for performance reasons, we usually do not register dozens
31+
of lint passes. Instead, we have a single lint pass of each variety
32+
(e.g. `BuiltinCombinedModuleLateLintPass`) which will internally call all of the
33+
individual lint passes; this is because then we get the benefits of static over
34+
dynamic dispatch for each of the (often empty) trait methods. Ideally, we'd not
35+
have to do this, since it certainly adds to the complexity of understanding the
36+
code. However, with the current type-erased lint store approach, it is
37+
beneficial to do so for performance reasons.
38+
39+
New lints being added likely want to join one of the existing declarations like
40+
`late_lint_mod_passes` in `librustc_lint/lib.rs`.

0 commit comments

Comments
 (0)