Skip to content

Commit 86319b6

Browse files
authored
Merge pull request rust-lang#2803 from rust-lang/tshepang/sembr
sembr a few files
2 parents 23bcfc1 + 61d960f commit 86319b6

File tree

7 files changed

+238
-165
lines changed

7 files changed

+238
-165
lines changed

src/doc/rustc-dev-guide/ci/sembr/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct Cli {
1515
/// Modify files that do not comply
1616
overwrite: bool,
1717
/// Applies to lines that are to be split
18-
#[arg(long, default_value_t = 100)]
18+
#[arg(long, default_value_t = 80)]
1919
line_length_limit: usize,
2020
}
2121

Lines changed: 72 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
# Member constraints
22

33
A member constraint `'m member of ['c_1..'c_N]` expresses that the
4-
region `'m` must be *equal* to some **choice regions** `'c_i` (for
5-
some `i`). These constraints cannot be expressed by users, but they
6-
arise from `impl Trait` due to its lifetime capture rules. Consider a
7-
function such as the following:
4+
region `'m` must be *equal* to some **choice regions** `'c_i` (for some `i`).
5+
These constraints cannot be expressed by users, but they
6+
arise from `impl Trait` due to its lifetime capture rules.
7+
Consider a function such as the following:
88

99
```rust,ignore
1010
fn make(a: &'a u32, b: &'b u32) -> impl Trait<'a, 'b> { .. }
1111
```
1212

1313
Here, the true return type (often called the "hidden type") is only
14-
permitted to capture the lifetimes `'a` or `'b`. You can kind of see
14+
permitted to capture the lifetimes `'a` or `'b`.
15+
You can kind of see
1516
this more clearly by desugaring that `impl Trait` return type into its
1617
more explicit form:
1718

@@ -23,16 +24,17 @@ fn make(a: &'a u32, b: &'b u32) -> MakeReturn<'a, 'b> { .. }
2324
Here, the idea is that the hidden type must be some type that could
2425
have been written in place of the `impl Trait<'x, 'y>` -- but clearly
2526
such a type can only reference the regions `'x` or `'y` (or
26-
`'static`!), as those are the only names in scope. This limitation is
27+
`'static`!), as those are the only names in scope.
28+
This limitation is
2729
then translated into a restriction to only access `'a` or `'b` because
2830
we are returning `MakeReturn<'a, 'b>`, where `'x` and `'y` have been
2931
replaced with `'a` and `'b` respectively.
3032

3133
## Detailed example
3234

3335
To help us explain member constraints in more detail, let's spell out
34-
the `make` example in a bit more detail. First off, let's assume that
35-
you have some dummy trait:
36+
the `make` example in a bit more detail.
37+
First off, let's assume that you have some dummy trait:
3638

3739
```rust,ignore
3840
trait Trait<'a, 'b> { }
@@ -49,8 +51,8 @@ fn make(a: &'a u32, b: &'b u32) -> MakeReturn<'a, 'b> {
4951
```
5052

5153
What happens in this case is that the return type will be `(&'0 u32, &'1 u32)`,
52-
where `'0` and `'1` are fresh region variables. We will have the following
53-
region constraints:
54+
where `'0` and `'1` are fresh region variables.
55+
We will have the following region constraints:
5456

5557
```txt
5658
'0 live at {L}
@@ -67,11 +69,11 @@ return tuple is constructed to where it is returned (in fact, `'0` and
6769
`'1` might have slightly different liveness sets, but that's not very
6870
interesting to the point we are illustrating here).
6971

70-
The `'a: '0` and `'b: '1` constraints arise from subtyping. When we
71-
construct the `(a, b)` value, it will be assigned type `(&'0 u32, &'1
72+
The `'a: '0` and `'b: '1` constraints arise from subtyping.
73+
When we construct the `(a, b)` value, it will be assigned type `(&'0 u32, &'1
7274
u32)` -- the region variables reflect that the lifetimes of these
73-
references could be made smaller. For this value to be created from
74-
`a` and `b`, however, we do require that:
75+
references could be made smaller.
76+
For this value to be created from `a` and `b`, however, we do require that:
7577

7678
```txt
7779
(&'a u32, &'b u32) <: (&'0 u32, &'1 u32)
@@ -82,35 +84,39 @@ which means in turn that `&'a u32 <: &'0 u32` and hence that `'a: '0`
8284

8385
Note that if we ignore member constraints, the value of `'0` would be
8486
inferred to some subset of the function body (from the liveness
85-
constraints, which we did not write explicitly). It would never become
87+
constraints, which we did not write explicitly).
88+
It would never become
8689
`'a`, because there is no need for it too -- we have a constraint that
87-
`'a: '0`, but that just puts a "cap" on how *large* `'0` can grow to
88-
become. Since we compute the *minimal* value that we can, we are happy
89-
to leave `'0` as being just equal to the liveness set. This is where
90-
member constraints come in.
90+
`'a: '0`, but that just puts a "cap" on how *large* `'0` can grow to become.
91+
Since we compute the *minimal* value that we can, we are happy
92+
to leave `'0` as being just equal to the liveness set.
93+
This is where member constraints come in.
9194

9295
## Choices are always lifetime parameters
9396

9497
At present, the "choice" regions from a member constraint are always lifetime
9598
parameters from the current function. As of <!-- date-check --> March 2026,
9699
this falls out from the placement of impl Trait, though in the future it may not
97-
be the case. We take some advantage of this fact, as it simplifies the current
98-
code. In particular, we don't have to consider a case like `'0 member of ['1,
100+
be the case.
101+
We take some advantage of this fact, as it simplifies the current code.
102+
In particular, we don't have to consider a case like `'0 member of ['1,
99103
'static]`, in which the value of both `'0` and `'1` are being inferred and hence
100-
changing. See [rust-lang/rust#61773][#61773] for more information.
104+
changing.
105+
See [rust-lang/rust#61773][#61773] for more information.
101106

102107
[#61773]: https://github.com/rust-lang/rust/issues/61773
103108

104109
## Applying member constraints
105110

106-
Member constraints are a bit more complex than other forms of
107-
constraints. This is because they have a "or" quality to them -- that
111+
Member constraints are a bit more complex than other forms of constraints.
112+
This is because they have a "or" quality to them -- that
108113
is, they describe multiple choices that we must select from. E.g., in
109114
our example constraint `'0 member of ['a, 'b, 'static]`, it might be
110-
that `'0` is equal to `'a`, `'b`, *or* `'static`. How can we pick the
111-
correct one? What we currently do is to look for a *minimal choice*
112-
-- if we find one, then we will grow `'0` to be equal to that minimal
113-
choice. To find that minimal choice, we take two factors into
115+
that `'0` is equal to `'a`, `'b`, *or* `'static`.
116+
How can we pick the correct one?
117+
What we currently do is to look for a *minimal choice*
118+
-- if we find one, then we will grow `'0` to be equal to that minimal choice.
119+
To find that minimal choice, we take two factors into
114120
consideration: lower and upper bounds.
115121

116122
### Lower bounds
@@ -121,30 +127,34 @@ apply member constraints, we've already *computed* the lower bounds of
121127
`'0` because we computed its minimal value (or at least, the lower
122128
bounds considering everything but member constraints).
123129

124-
Let `LB` be the current value of `'0`. We know then that `'0: LB` must
125-
hold, whatever the final value of `'0` is. Therefore, we can rule out
130+
Let `LB` be the current value of `'0`.
131+
We know then that `'0: LB` must hold, whatever the final value of `'0` is.
132+
Therefore, we can rule out
126133
any choice `'choice` where `'choice: LB` does not hold.
127134

128-
Unfortunately, in our example, this is not very helpful. The lower
129-
bound for `'0` will just be the liveness set `{L}`, and we know that
130-
all the lifetime parameters outlive that set. So we are left with the
131-
same set of choices here. (But in other examples, particularly those
135+
Unfortunately, in our example, this is not very helpful.
136+
The lower bound for `'0` will just be the liveness set `{L}`, and we know that
137+
all the lifetime parameters outlive that set.
138+
So we are left with the same set of choices here.
139+
(But in other examples, particularly those
132140
with different variance, lower bound constraints may be relevant.)
133141

134142
### Upper bounds
135143

136144
The *upper bounds* are those lifetimes that *must outlive* `'0` --
137145
i.e., that `'0` must be *smaller* than. In our example, this would be
138-
`'a`, because we have the constraint that `'a: '0`. In more complex
139-
examples, the chain may be more indirect.
146+
`'a`, because we have the constraint that `'a: '0`.
147+
In more complex examples, the chain may be more indirect.
140148

141149
We can use upper bounds to rule out members in a very similar way to
142-
lower bounds. If UB is some upper bound, then we know that `UB:
150+
lower bounds.
151+
If UB is some upper bound, then we know that `UB:
143152
'0` must hold, so we can rule out any choice `'choice` where `UB:
144153
'choice` does not hold.
145154

146155
In our example, we would be able to reduce our choice set from `['a,
147-
'b, 'static]` to just `['a]`. This is because `'0` has an upper bound
156+
'b, 'static]` to just `['a]`.
157+
This is because `'0` has an upper bound
148158
of `'a`, and neither `'a: 'b` nor `'a: 'static` is known to hold.
149159

150160
(For notes on how we collect upper bounds in the implementation, see
@@ -153,39 +163,45 @@ of `'a`, and neither `'a: 'b` nor `'a: 'static` is known to hold.
153163
### Minimal choice
154164

155165
After applying lower and upper bounds, we can still sometimes have
156-
multiple possibilities. For example, imagine a variant of our example
157-
using types with the opposite variance. In that case, we would have
158-
the constraint `'0: 'a` instead of `'a: '0`. Hence the current value
159-
of `'0` would be `{L, 'a}`. Using this as a lower bound, we would be
166+
multiple possibilities.
167+
For example, imagine a variant of our example
168+
using types with the opposite variance.
169+
In that case, we would have the constraint `'0: 'a` instead of `'a: '0`.
170+
Hence the current value of `'0` would be `{L, 'a}`.
171+
Using this as a lower bound, we would be
160172
able to narrow down the member choices to `['a, 'static]` because `'b:
161-
'a` is not known to hold (but `'a: 'a` and `'static: 'a` do hold). We
162-
would not have any upper bounds, so that would be our final set of choices.
173+
'a` is not known to hold (but `'a: 'a` and `'static: 'a` do hold).
174+
We would not have any upper bounds, so that would be our final set of choices.
163175

164176
In that case, we apply the **minimal choice** rule -- basically, if
165-
one of our choices if smaller than the others, we can use that. In
166-
this case, we would opt for `'a` (and not `'static`).
177+
one of our choices if smaller than the others, we can use that.
178+
In this case, we would opt for `'a` (and not `'static`).
167179

168180
This choice is consistent with the general 'flow' of region
169181
propagation, which always aims to compute a minimal value for the
170-
region being inferred. However, it is somewhat arbitrary.
182+
region being inferred.
183+
However, it is somewhat arbitrary.
171184

172185
<a id="collecting"></a>
173186

174187
### Collecting upper bounds in the implementation
175188

176189
In practice, computing upper bounds is a bit inconvenient, because our
177-
data structures are setup for the opposite. What we do is to compute
190+
data structures are setup for the opposite.
191+
What we do is to compute
178192
the **reverse SCC graph** (we do this lazily and cache the result) --
179-
that is, a graph where `'a: 'b` induces an edge `SCC('b) ->
180-
SCC('a)`. Like the normal SCC graph, this is a DAG. We can then do a
181-
depth-first search starting from `SCC('0)` in this graph. This will
182-
take us to all the SCCs that must outlive `'0`.
193+
that is, a graph where `'a: 'b` induces an edge `SCC('b) -> SCC('a)`.
194+
Like the normal SCC graph, this is a DAG.
195+
We can then do a depth-first search starting from `SCC('0)` in this graph.
196+
This will take us to all the SCCs that must outlive `'0`.
183197

184198
One wrinkle is that, as we walk the "upper bound" SCCs, their values
185-
will not yet have been fully computed. However, we **have** already
199+
will not yet have been fully computed.
200+
However, we **have** already
186201
applied their liveness constraints, so we have some information about
187-
their value. In particular, for any regions representing lifetime
202+
their value.
203+
In particular, for any regions representing lifetime
188204
parameters, their value will contain themselves (i.e., the initial
189-
value for `'a` includes `'a` and the value for `'b` contains `'b`). So
190-
we can collect all of the lifetime parameters that are reachable,
205+
value for `'a` includes `'a` and the value for `'b` contains `'b`).
206+
So we can collect all of the lifetime parameters that are reachable,
191207
which is precisely what we are interested in.

src/doc/rustc-dev-guide/src/diagnostics/lintstore.md

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
This page documents some of the machinery around lint registration and how we
44
run lints in the compiler.
55

6-
The [`LintStore`] is the central piece of infrastructure, around which
7-
everything rotates. The `LintStore` is held as part of the [`Session`], and it
6+
The [`LintStore`] is the central piece of infrastructure, around which everything rotates.
7+
The `LintStore` is held as part of the [`Session`], and it
88
gets populated with the list of lints shortly after the `Session` is created.
99

1010
## Lints vs. lint passes
1111

12-
There are two parts to the linting mechanism within the compiler: lints and
13-
lint passes. Unfortunately, a lot of the documentation we have refers to both
14-
of these as just "lints."
12+
There are two parts to the linting mechanism within the compiler: lints and lint passes.
13+
Unfortunately, a lot of the documentation we have refers to both of these as just "lints."
1514

1615
First, we have the lint declarations themselves,
1716
and this is where the name and default lint level and other metadata come from.
@@ -24,10 +23,11 @@ like all macros).
2423
we lint against direct declarations without the use of the macro.
2524

2625
Lint declarations don't carry any "state" - they are merely global identifiers
27-
and descriptions of lints. We assert at runtime that they are not registered
28-
twice (by lint name).
26+
and descriptions of lints.
27+
We assert at runtime that they are not registered twice (by lint name).
2928

30-
Lint passes are the meat of any lint. Notably, there is not a one-to-one
29+
Lint passes are the meat of any lint.
30+
Notably, there is not a one-to-one
3131
relationship between lints and lint passes; a lint might not have any lint pass
3232
that emits it, it could have many, or just one -- the compiler doesn't track
3333
whether a pass is in any way associated with a particular lint, and frequently
@@ -44,36 +44,33 @@ and all lints are registered.
4444
There are three 'sources' of lints:
4545

4646
* internal lints: lints only used by the rustc codebase
47-
* builtin lints: lints built into the compiler and not provided by some outside
48-
source
49-
* `rustc_interface::Config`[`register_lints`]: lints passed into the compiler
50-
during construction
47+
* builtin lints: lints built into the compiler and not provided by some outside source
48+
* `rustc_interface::Config`[`register_lints`]: lints passed into the compiler during construction
5149

52-
Lints are registered via the [`LintStore::register_lint`] function. This should
53-
happen just once for any lint, or an ICE will occur.
50+
Lints are registered via the [`LintStore::register_lint`] function.
51+
This should happen just once for any lint, or an ICE will occur.
5452

55-
Once the registration is complete, we "freeze" the lint store by placing it in
56-
an `Arc`.
53+
Once the registration is complete, we "freeze" the lint store by placing it in an `Arc`.
5754

5855
Lint passes are registered separately into one of the categories
59-
(pre-expansion, early, late, late module). Passes are registered as a closure
56+
(pre-expansion, early, late, late module).
57+
Passes are registered as a closure
6058
-- i.e., `impl Fn() -> Box<dyn X>`, where `dyn X` is either an early or late
61-
lint pass trait object. When we run the lint passes, we run the closure and
62-
then invoke the lint pass methods. The lint pass methods take `&mut self` so
63-
they can keep track of state internally.
59+
lint pass trait object.
60+
When we run the lint passes, we run the closure and then invoke the lint pass methods.
61+
The lint pass methods take `&mut self` so they can keep track of state internally.
6462

6563
#### Internal lints
6664

67-
These are lints used just by the compiler or drivers like `clippy`. They can be
68-
found in [`rustc_lint::internal`].
65+
These are lints used just by the compiler or drivers like `clippy`.
66+
They can be found in [`rustc_lint::internal`].
6967

7068
An example of such a lint is the check that lint passes are implemented using
71-
the `declare_lint_pass!` macro and not by hand. This is accomplished with the
72-
`LINT_PASS_IMPL_WITHOUT_MACRO` lint.
69+
the `declare_lint_pass!` macro and not by hand.
70+
This is accomplished with the `LINT_PASS_IMPL_WITHOUT_MACRO` lint.
7371

7472
Registration of these lints happens in the [`rustc_lint::register_internals`]
75-
function which is called when constructing a new lint store inside
76-
[`rustc_lint::new_lint_store`].
73+
function which is called when constructing a new lint store inside [`rustc_lint::new_lint_store`].
7774

7875
#### Builtin Lints
7976

@@ -83,19 +80,18 @@ Often the first provides the definitions for the lints themselves,
8380
and the latter provides the lint pass definitions (and implementations),
8481
but this is not always true.
8582

86-
The builtin lint registration happens in
87-
the [`rustc_lint::register_builtins`] function.
83+
The builtin lint registration happens in the [`rustc_lint::register_builtins`] function.
8884
Just like with internal lints,
8985
this happens inside of [`rustc_lint::new_lint_store`].
9086

9187
#### Driver lints
9288

9389
These are the lints provided by drivers via the `rustc_interface::Config`
94-
[`register_lints`] field, which is a callback. Drivers should, if finding it
95-
already set, call the function currently set within the callback they add. The
96-
best way for drivers to get access to this is by overriding the
97-
`Callbacks::config` function which gives them direct access to the `Config`
98-
structure.
90+
[`register_lints`] field, which is a callback.
91+
Drivers should, if finding it
92+
already set, call the function currently set within the callback they add.
93+
The best way for drivers to get access to this is by overriding the
94+
`Callbacks::config` function which gives them direct access to the `Config` structure.
9995

10096
## Compiler lint passes are combined into one pass
10197

@@ -105,8 +101,8 @@ of lint passes. Instead, we have a single lint pass of each variety (e.g.,
105101
individual lint passes; this is because then we get the benefits of static over
106102
dynamic dispatch for each of the (often empty) trait methods.
107103

108-
Ideally, we'd not have to do this, since it adds to the complexity of
109-
understanding the code. However, with the current type-erased lint store
104+
Ideally, we'd not have to do this, since it adds to the complexity of understanding the code.
105+
However, with the current type-erased lint store
110106
approach, it is beneficial to do so for performance reasons.
111107

112108
[`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html

0 commit comments

Comments
 (0)