Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 18 additions & 22 deletions src/borrow-check.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
# MIR borrow check

The borrow check is Rust's "secret sauce" – it is tasked with
enforcing a number of properties:
The borrow check is Rust's "secret sauce" – it is tasked with enforcing a number of properties:

- That all variables are initialized before they are used.
- That you can't move the same value twice.
- That you can't move a value while it is borrowed.
- That you can't access a place while it is mutably borrowed (except through
the reference).
- That you can't access a place while it is mutably borrowed (except through the reference).
- That you can't mutate a place while it is immutably borrowed.
- etc

The borrow checker operates on the MIR. An older implementation operated on the
HIR. Doing borrow checking on MIR has several advantages:
The borrow checker operates on the MIR.
An older implementation operated on the HIR.
Doing borrow checking on MIR has several advantages:

- The MIR is *far* less complex than the HIR; the radical desugaring
helps prevent bugs in the borrow checker. (If you're curious, you
can see
helps prevent bugs in the borrow checker.
(If you're curious, you can see
[a list of bugs that the MIR-based borrow checker fixes here][47366].)
- Even more importantly, using the MIR enables ["non-lexical lifetimes"][nll],
which are regions derived from the control-flow graph.
Expand All @@ -26,35 +25,32 @@ HIR. Doing borrow checking on MIR has several advantages:

## Major phases of the borrow checker

The borrow checker source is found in
[the `rustc_borrowck` crate][b_c]. The main entry point is
the [`mir_borrowck`] query.
The borrow checker source is found in [the `rustc_borrowck` crate][b_c].
The main entry point is the [`mir_borrowck`] query.

[b_c]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/index.html
[`mir_borrowck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/fn.mir_borrowck.html

- We first create a **local copy** of the MIR. In the coming steps,
- We first create a **local copy** of the MIR.
In the coming steps,
we will modify this copy in place to modify the types and things to
include references to the new regions that we are computing.
- We then invoke [`replace_regions_in_mir`] to modify our local MIR.
Among other things, this function will replace all of the [regions](./appendix/glossary.md#region)
in the MIR with fresh [inference variables](./appendix/glossary.md#inf-var).
- Next, we perform a number of
[dataflow analyses](./appendix/background.md#dataflow) that
- Next, we perform a number of [dataflow analyses](./appendix/background.md#dataflow) that
compute what data is moved and when.
- We then do a [second type check](borrow-check/type-check.md) across the MIR:
the purpose of this type check is to determine all of the constraints between
different regions.
the purpose of this type check is to determine all of the constraints between different regions.
- Next, we do [region inference](borrow-check/region-inference.md), which computes
the values of each region — basically, the points in the control-flow graph where
each lifetime must be valid according to the constraints we collected.
- At this point, we can compute the "borrows in scope" at each point.
- Finally, we do a second walk over the MIR, looking at the actions it
does and reporting errors. For example, if we see a statement like
`*a + 1`, then we would check that the variable `a` is initialized
and that it is not mutably borrowed, as either of those would
require an error to be reported. Doing this check requires the results of all
the previous analyses.
- Finally, we do a second walk over the MIR, looking at the actions it does and reporting errors.
For example, if we see a statement like `*a + 1`,
we would check that the variable `a` is initialized and that it is not mutably borrowed,
as either of those would require an error to be reported.
Doing this check requires the results of all the previous analyses.

[`replace_regions_in_mir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/nll/fn.replace_regions_in_mir.html

Expand Down
23 changes: 12 additions & 11 deletions src/borrow-check/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@

With `-Z dump-mir-graphviz=yes`, you will also get Graphviz files for the outlives constraints
of the MIR bodies you asked for, as well as the strongly connected components (SCCs) on them.
They are available as
`mir_dump/rs-file-name.function-name.-------.nll.0.regioncx.all.dot` and
`mir_dump/rs-file-name.function-name.-------.nll.0.regioncx.scc.dot` respectively. For both
graphs, named region variables will be shown with their external name (such as `'static`)
shown in parenthesis. For region inference variables in universes other than the root universe,
they will be shown as `/U13` (for universe 13). In the region graph, edges are labelled with
the MIR location where the relationship is required to hold, or `All` if the constraint should
always be true.
They are available as `mir_dump/rs-file-name.function-name.-------.nll.0.regioncx.all.dot` and
`mir_dump/rs-file-name.function-name.-------.nll.0.regioncx.scc.dot` respectively.
For both graphs, named region variables will be shown with their external name (such as `'static`)
shown in parenthesis.
For region inference variables in universes other than the root universe,
they will be shown as `/U13` (for universe 13).
In the region graph,
edges are labelled with the MIR location where the relationship is required to hold,
or `All` if the constraint should always be true.

![A graph showing a small number of strongly connected components on the region-
outlives-graph above](../img/scc-graphviz.png)

**Note:** There are implicit edges from `'static` to every region, but those are not
rendered
in the region graph to avoid clutter. They _do_ however show up in the SCC graph.
**Note:** There are implicit edges from `'static` to every region, but those are not rendered
in the region graph to avoid clutter.
They _do_ however show up in the SCC graph.
This is why there are outgoing edges from `SCC(5)` in the SCC graph that do not seem
to have corresponding edges in the region outlives graph above.

Expand Down
7 changes: 3 additions & 4 deletions src/compiler-debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ This chapter contains a few tips to debug the compiler.
These tips aim to be useful no matter what you are working on.
Some of the other chapters have
advice about specific parts of the compiler (e.g. the [Queries Debugging and
Testing chapter](./incrcomp-debugging.md) or the [LLVM Debugging
chapter](./backend/debugging.md)).
Testing chapter](./incrcomp-debugging.md) or the [LLVM Debugging chapter](./backend/debugging.md)).

## Configuring the compiler

Expand Down Expand Up @@ -317,8 +316,8 @@ $ firefox maybe_init_suffix.pdf # Or your favorite pdf viewer

Graphviz also comes with a preprocessor program,
[`unflatten`](https://graphviz.org/docs/cli/unflatten/), that
sometimes helps making the outputs look less oddly spread out. It reads
a dot file and outputs another dot file, so you can use it in a pipe,
sometimes helps making the outputs look less oddly spread out.
It reads a dot file and outputs another dot file, so you can use it in a pipe,
e.g:
```
$ unflatten mir_dump/*.foo.-------.nll.0.regioncx.all.dot | dot -Tpdf -o foo-outlives.pdf
Expand Down
8 changes: 4 additions & 4 deletions src/debuginfo/lldb-visualizers.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ The bool returned from this function is somewhat complicated, see:
[`update` caching](#update-caching) below for more info.
When in doubt, return `False`/`None`.
As of <!-- date-check --> Nov 2025,
none of the visualizers return `True`, but that may change as the debug info
test suite is improved.
none of the visualizers return `True`, but that may change as the debug info test suite is improved.

#### `update` caching

Expand Down Expand Up @@ -348,8 +347,9 @@ The category we use will be called `Rust`.
description, list of arguments, and examples.

In the past, we used `command source ...`, which executes a series of CLI commands from the
file `lldb_commands` to add providers. This file was somewhat unwieldy, and has been supplanted by
the Python API equivalent outlined below.
file `lldb_commands` to add providers.
This file was somewhat unwieldy,
and has been supplanted by the Python API equivalent outlined below.

## `__lldb_init_module`

Expand Down
Loading
Loading