about summary refs log tree commit diff
path: root/src/doc/rustc-dev-guide
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-03-19 09:35:41 -0400
committerGitHub <noreply@github.com>2018-03-19 09:35:41 -0400
commitfa0c7fb2668314f28546e9a5617f2a86b3c067ad (patch)
tree2c150874dee9e621745a15fa0b6a4e23ced2b23c /src/doc/rustc-dev-guide
parent27d1918c071c33abb9fc8072d7ab4a7d80b882e3 (diff)
parent93cf9a80068a22b621490849f081d29ffe28e89c (diff)
Merge pull request #92 from mark-i-m/deptrack
Add incremental compilation debugging subchapter
Diffstat (limited to 'src/doc/rustc-dev-guide')
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md1
-rw-r--r--src/doc/rustc-dev-guide/src/incrcomp-debugging.md113
2 files changed, 114 insertions, 0 deletions
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 3079c0b48ac..47775e29c87 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -13,6 +13,7 @@
     - [Rustdoc](./rustdoc.md)
 - [Queries: demand-driven compilation](./query.md)
     - [Incremental compilation](./incremental-compilation.md)
+    - [Debugging and Testing](./incrcomp-debugging.md)
 - [The parser](./the-parser.md)
 - [Macro expansion](./macro-expansion.md)
 - [Name resolution](./name-resolution.md)
diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md
new file mode 100644
index 00000000000..92a8e10ea3c
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md
@@ -0,0 +1,113 @@
+# Debugging and Testing Dependencies
+
+## Testing the dependency graph
+
+There are various ways to write tests against the dependency graph.
+The simplest mechanisms are the `#[rustc_if_this_changed]` and
+`#[rustc_then_this_would_need]` annotations. These are used in compile-fail
+tests to test whether the expected set of paths exist in the dependency graph.
+As an example, see `src/test/compile-fail/dep-graph-caller-callee.rs`.
+
+The idea is that you can annotate a test like:
+
+```rust
+#[rustc_if_this_changed]
+fn foo() { }
+
+#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK
+fn bar() { foo(); }
+
+#[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path
+fn baz() { }
+```
+
+This will check whether there is a path in the dependency graph from `Hir(foo)`
+to `TypeckTables(bar)`. An error is reported for each
+`#[rustc_then_this_would_need]` annotation that indicates whether a path
+exists. `//~ ERROR` annotations can then be used to test if a path is found (as
+demonstrated above).
+
+## Debugging the dependency graph
+
+### Dumping the graph
+
+The compiler is also capable of dumping the dependency graph for your
+debugging pleasure. To do so, pass the `-Z dump-dep-graph` flag. The
+graph will be dumped to `dep_graph.{txt,dot}` in the current
+directory.  You can override the filename with the `RUST_DEP_GRAPH`
+environment variable.
+
+Frequently, though, the full dep graph is quite overwhelming and not
+particularly helpful. Therefore, the compiler also allows you to filter
+the graph. You can filter in three ways:
+
+1. All edges originating in a particular set of nodes (usually a single node).
+2. All edges reaching a particular set of nodes.
+3. All edges that lie between given start and end nodes.
+
+To filter, use the `RUST_DEP_GRAPH_FILTER` environment variable, which should
+look like one of the following:
+
+```
+source_filter     // nodes originating from source_filter
+-> target_filter  // nodes that can reach target_filter
+source_filter -> target_filter // nodes in between source_filter and target_filter
+```
+
+`source_filter` and `target_filter` are a `&`-separated list of strings.
+A node is considered to match a filter if all of those strings appear in its
+label. So, for example:
+
+```
+RUST_DEP_GRAPH_FILTER='-> TypeckTables'
+```
+
+would select the predecessors of all `TypeckTables` nodes. Usually though you
+want the `TypeckTables` node for some particular fn, so you might write:
+
+```
+RUST_DEP_GRAPH_FILTER='-> TypeckTables & bar'
+```
+
+This will select only the predecessors of `TypeckTables` nodes for functions with
+`bar` in their name.
+
+Perhaps you are finding that when you change `foo` you need to re-type-check `bar`,
+but you don't think you should have to. In that case, you might do:
+
+```
+RUST_DEP_GRAPH_FILTER='Hir & foo -> TypeckTables & bar'
+```
+
+This will dump out all the nodes that lead from `Hir(foo)` to
+`TypeckTables(bar)`, from which you can (hopefully) see the source
+of the erroneous edge.
+
+### Tracking down incorrect edges
+
+Sometimes, after you dump the dependency graph, you will find some
+path that should not exist, but you will not be quite sure how it came
+to be. **When the compiler is built with debug assertions,** it can
+help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE`
+environment variable to a filter. Every edge created in the dep-graph
+will be tested against that filter -- if it matches, a `bug!` is
+reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`).
+
+The syntax for these filters is the same as described in the previous
+section. However, note that this filter is applied to every **edge**
+and doesn't handle longer paths in the graph, unlike the previous
+section.
+
+Example:
+
+You find that there is a path from the `Hir` of `foo` to the type
+check of `bar` and you don't think there should be. You dump the
+dep-graph as described in the previous section and open `dep-graph.txt`
+to see something like:
+
+    Hir(foo) -> Collect(bar)
+    Collect(bar) -> TypeckTables(bar)
+
+That first edge looks suspicious to you. So you set
+`RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and
+then observe the backtrace. Voila, bug fixed!