Skip to content

Commit d97ddcd

Browse files
restructure
1 parent ac4f927 commit d97ddcd

File tree

1 file changed

+87
-22
lines changed

1 file changed

+87
-22
lines changed

src/diagnostics/lintstore.md

+87-22
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,105 @@
1-
# LintStore
1+
# Lints
22

33
This page documents some of the machinery around lint registration and how we
44
run lints in the compiler.
55

66
The `LintStore` is the central piece of infrastructure, around which everything
77
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.
8+
TyCtxt) in most code, as we need to fill it in with all of the lints, which can only happen after
9+
plugin registration.
1010

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.
11+
## Lints vs. lint passes
1712

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.
13+
There are two parts to the linting mechanism within the compiler: lints and lint passes.
14+
Unfortunately, a lot of the documentation we have refers to both of these as just "lints."
15+
16+
First, we have the lint declarations themselves: this is where the name and default lint level and
17+
other metadata come from. These are normally defined by way of the [`declare_lint!`] macro, which
18+
boils down to a static with type `&rustc::lint::Lint`. We lint against direct declarations without
19+
the use of the macro today (though this may change in the future, as the macro is somewhat unwieldy
20+
to add new fields to, like all macros by example).
21+
22+
Lint declarations don't carry any "state" - they are merely global identifers and descriptions of
23+
lints. We assert at runtime that they are not registered twice (by lint name).
24+
25+
Lint passes are the meat of any lint. Notably, there is not a one-to-one relationship between
26+
lints and lint passes; a lint might not have any lint pass that emits it, it could have many, or
27+
just one -- the compiler doesn't track whether a pass is in any way associated with a particular
28+
lint, and frequently lints are emitted as part of other work (e.g., type checking, etc.).
2229

2330
## Registration
2431

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))`.
32+
### High-level overview
33+
34+
The lint store is created and all lints are registered during plugin registration, in
35+
[`rustc_interface::register_plugins`]. There are three 'sources' of lint: the internal lints, plugin
36+
lints, and `rustc_interface::Config` `register_lints`. All are registered here, in
37+
`register_plugins`.
38+
39+
Once the registration is complete, we "freeze" the lint store by placing it in an `Lrc`. Later in
40+
the driver, it's passed into the `GlobalCtxt` constructor where it lives in an immutable form from
41+
then on.
42+
43+
Lints are registered via the [`LintStore::register_lint`] function. This should
44+
happen just once for any lint, or an ICE will occur.
45+
46+
Lint passes are registered separately into one of the categories (pre-expansion,
47+
early, late, late module). Passes are registered as a closure -- i.e., `impl
48+
Fn() -> Box<dyn X>`, where `dyn X` is either an early or late lint pass trait
49+
object. When we run the lint passes, we run the closure and then invoke the lint
50+
pass methods, which take `&mut self` -- lint passes can keep track of state
51+
internally.
52+
53+
#### Internal lints
54+
55+
Note, these include both rustc-internal lints, and the traditional lints, like, for example the dead
56+
code lint.
57+
58+
These are primarily described in two places: `rustc::lint::builtin` and `rustc_lint::builtin`. The
59+
first provides the definitions for the lints themselves, and the latter provides the lint pass
60+
definitions (and implementations).
61+
62+
The internal lint registration happens in the [`rustc_lint::register_builtins`] function, along with
63+
the [`rustc_lint::register_internals`] function. More generally, the LintStore "constructor"
64+
function which is *the* way to get a `LintStore` in the compiler (you should not construct it
65+
directly) is [`rustc_lint::new_lint_store`]; it calls the registration functions.
66+
67+
#### Plugin lints
68+
69+
This is one of the primary use cases remaining for plugins/drivers. Plugins are given access to the
70+
mutable `LintStore` during registration to call any functions they need on the `LintStore`, just
71+
like rustc code. Plugins are intended to declare lints with the `plugin` field set to true (e.g., by
72+
way of the [`declare_tool_lint!`] macro), but this is purely for diagnostics and help text;
73+
otherwise plugin lints are mostly just as first class as rustc builtin lints.
74+
75+
#### Driver lints
76+
77+
These are the lints provided by drivers via the `rustc_interface::Config` [`register_lints`] field,
78+
which is a callback. Drivers should, if finding it already set, call the function currently set
79+
within the callback they add. The best way for drivers to get access to this is by overriding the
80+
`Callbacks::config` function which gives them direct access to the `Config` structure.
81+
82+
## Compiler lint passes are combined into one pass
2983

3084
Within the compiler, for performance reasons, we usually do not register dozens
3185
of lint passes. Instead, we have a single lint pass of each variety
3286
(e.g. `BuiltinCombinedModuleLateLintPass`) which will internally call all of the
3387
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.
88+
dynamic dispatch for each of the (often empty) trait methods.
89+
90+
Ideally, we'd not have to do this, since it certainly adds to the complexity of
91+
understanding the code. However, with the current type-erased lint store
92+
approach, it is beneficial to do so for performance reasons.
3893

3994
New lints being added likely want to join one of the existing declarations like
40-
`late_lint_mod_passes` in `librustc_lint/lib.rs`.
95+
`late_lint_mod_passes` in `librustc_lint/lib.rs`, which would then
96+
auto-propagate into the other.
97+
98+
[`LintStore::register_lint`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/struct.LintStore.html#method.register_lints
99+
[`rustc_interface::register_plugins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/passes/fn.register_plugins.html)
100+
[`rustc_lint::register_builtins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html
101+
[`rustc_lint::register_internals`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_internals.html
102+
[`rustc_lint::new_lint_store`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.new_lint_store.html
103+
[`rustc::declare_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/macro.declare_lint.html
104+
[`rustc::declare_tool_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/macro.declare_tool_lint.html
105+
[`register_lints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html#structfield.register_lints

0 commit comments

Comments
 (0)