3
3
This page documents some of the machinery around lint registration and how we
4
4
run lints in the compiler.
5
5
6
- The ` LintStore ` is the central piece of infrastructure, around which everything
6
+ The [ ` LintStore ` ] is the central piece of infrastructure, around which everything
7
7
rotates. It's not available during the early parts of compilation (i.e., before
8
8
TyCtxt) in most code, as we need to fill it in with all of the lints, which can only happen after
9
9
plugin registration.
@@ -19,8 +19,7 @@ boils down to a static with type `&rustc_session::lint::Lint`.
19
19
20
20
As of <!-- date: 2021-07 --> July 2021, we lint against direct declarations
21
21
without the use of the macro today (although this may change in the future, as
22
- the macro is somewhat unwieldy to add new fields to, like all macros by
23
- example).
22
+ the macro is somewhat unwieldy to add new fields to, like all macros).
24
23
25
24
Lint declarations don't carry any "state" - they are merely global identifers and descriptions of
26
25
lints. We assert at runtime that they are not registered twice (by lint name).
@@ -34,44 +33,55 @@ lint, and frequently lints are emitted as part of other work (e.g., type checkin
34
33
35
34
### High-level overview
36
35
37
- The lint store is created and all lints are registered during plugin registration, in
38
- [ ` rustc_interface::register_plugins ` ] . There are three 'sources' of lint: the internal lints, plugin
39
- lints, and ` rustc_interface::Config ` [ ` register_lints ` ] . All are registered here, in
40
- ` register_plugins ` .
36
+ In [ ` rustc_interface::register_plugins ` ] the [ ` LintStore ` ] is created and all lints are registered.
37
+ There are four 'sources' of lints:
38
+ * internal lints: lints only used by the rustc codebase
39
+ * builtin lints: lints built into the compiler and not provided by some outside source
40
+ * plugin lints: lints created by plugins through the plugin system.
41
+ * ` rustc_interface::Config ` [ ` register_lints ` ] : lints passed into the compiler during construction
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.
41
45
42
46
Once the registration is complete, we "freeze" the lint store by placing it in an ` Lrc ` . Later in
43
47
the driver, it's passed into the ` GlobalCtxt ` constructor where it lives in an immutable form from
44
48
then on.
45
49
46
- Lints are registered via the [ ` LintStore::register_lint ` ] function. This should
47
- happen just once for any lint, or an ICE will occur.
48
-
49
50
Lint passes are registered separately into one of the categories (pre-expansion,
50
51
early, late, late module). Passes are registered as a closure -- i.e., `impl
51
52
Fn() -> Box<dyn X >` , where ` dyn X` is either an early or late lint pass trait
52
53
object. When we run the lint passes, we run the closure and then invoke the lint
53
- pass methods, which take ` &mut self ` -- lint passes can keep track of state
54
+ pass methods. The lint pass methods take ` &mut self ` so they can keep track of state
54
55
internally.
55
56
56
57
#### Internal lints
57
58
58
- Note, these include both rustc-internal lints, and the traditional lints, like, for example the dead
59
- code lint.
59
+ These are lints used just by the compiler or plugins like ` clippy ` . They can be found in
60
+ ` rustc_lint::internal ` .
61
+
62
+ An example of such a lint is the check that lint passes are implemented using the ` declare_lint_pass! `
63
+ macro and not by hand. This is accomplished with the ` LINT_PASS_IMPL_WITHOUT_MACRO ` lint.
64
+
65
+ Registration of these lints happens in the [ ` rustc_lint::register_internals ` ] function which is
66
+ called when constructing a new lint store inside [ ` rustc_lint::new_lint_store ` ] .
67
+
68
+ ### Builtin Lints
60
69
61
70
These are primarily described in two places: ` rustc_session::lint::builtin ` and
62
- ` rustc_lint::builtin ` . The first provides the definitions for the lints themselves,
63
- and the latter provides the lint pass definitions (and implementations).
71
+ ` rustc_lint::builtin ` . Often the first provides the definitions for the lints themselves,
72
+ and the latter provides the lint pass definitions (and implementations), but this is not always
73
+ true.
64
74
65
- The internal lint registration happens in the [ ` rustc_lint::register_builtins ` ] function, along with
66
- the [ ` rustc_lint::register_internals ` ] function. More generally, the LintStore "constructor"
67
- function which is * the* way to get a ` LintStore ` in the compiler (you should not construct it
68
- directly) is [ ` rustc_lint::new_lint_store ` ] ; it calls the registration functions.
75
+ The builtin lint registration happens in the [ ` rustc_lint::register_builtins ` ] function. Just like
76
+ with internal lints, this happens inside of [ ` rustc_lint::new_lint_store ` ] .
69
77
70
78
#### Plugin lints
71
79
72
80
This is one of the primary use cases remaining for plugins/drivers. Plugins are given access to the
73
- mutable ` LintStore ` during registration to call any functions they need on the ` LintStore ` , just
74
- like rustc code. Plugins are intended to declare lints with the ` plugin ` field set to true (e.g., by
81
+ mutable ` LintStore ` during registration (which happens inside of [ ` rustc_interface::register_plugins ` ] )
82
+ and they can call any functions they need on the ` LintStore ` , just like rustc code.
83
+
84
+ Plugins are intended to declare lints with the ` plugin ` field set to true (e.g., by
75
85
way of the [ ` declare_tool_lint! ` ] macro), but this is purely for diagnostics and help text;
76
86
otherwise plugin lints are mostly just as first class as rustc builtin lints.
77
87
@@ -86,18 +96,15 @@ within the callback they add. The best way for drivers to get access to this is
86
96
87
97
Within the compiler, for performance reasons, we usually do not register dozens
88
98
of lint passes. Instead, we have a single lint pass of each variety
89
- (e.g. ` BuiltinCombinedModuleLateLintPass ` ) which will internally call all of the
99
+ (e.g., ` BuiltinCombinedModuleLateLintPass ` ) which will internally call all of the
90
100
individual lint passes; this is because then we get the benefits of static over
91
101
dynamic dispatch for each of the (often empty) trait methods.
92
102
93
- Ideally, we'd not have to do this, since it certainly adds to the complexity of
103
+ Ideally, we'd not have to do this, since it adds to the complexity of
94
104
understanding the code. However, with the current type-erased lint store
95
105
approach, it is beneficial to do so for performance reasons.
96
106
97
- New lints being added likely want to join one of the existing declarations like
98
- ` late_lint_mod_passes ` in ` rustc_lint/src/lib.rs ` , which would then
99
- auto-propagate into the other.
100
-
107
+ [ `LintStore` ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html
101
108
[ `LintStore::register_lint` ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_lints
102
109
[ `rustc_interface::register_plugins` ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/passes/fn.register_plugins.html
103
110
[ `rustc_lint::register_builtins` ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html
0 commit comments