rustc-dev-guide/incrcomp-debugging.html

309 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Debugging and testing - Rust Compiler Development Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust Compiler Development Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/master/src/incrcomp-debugging.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="debugging-and-testing-dependencies"><a class="header" href="#debugging-and-testing-dependencies">Debugging and testing dependencies</a></h1>
<h2 id="testing-the-dependency-graph"><a class="header" href="#testing-the-dependency-graph">Testing the dependency graph</a></h2>
<p>There are various ways to write tests against the dependency graph. The
simplest mechanisms are the <code>#[rustc_if_this_changed]</code> and
<code>#[rustc_then_this_would_need]</code> annotations. These are used in <a href="tests/ui.html">ui</a> tests to test
whether the expected set of paths exist in the dependency graph.</p>
<p>As an example, see <a href="https://github.com/rust-lang/rust/blob/master/tests/ui/dep-graph/dep-graph-caller-callee.rs"><code>tests/ui/dep-graph/dep-graph-caller-callee.rs</code></a>, or the
tests below.</p>
<pre><code class="language-rust ignore">#[rustc_if_this_changed]
fn foo() { }
#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK
fn bar() { foo(); }</code></pre>
<p>This should be read as</p>
<blockquote>
<p>If this (<code>foo</code>) is changed, then this (i.e. <code>bar</code>)'s TypeckTables would need to be changed.</p>
</blockquote>
<p>Technically, what occurs is that the test is expected to emit the string "OK" on
stderr, associated to this line.</p>
<p>You could also add the lines</p>
<pre><code class="language-rust ignore">#[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path
fn baz() { }</code></pre>
<p>Whose meaning is</p>
<blockquote>
<p>If <code>foo</code> is changed, then <code>baz</code>'s TypeckTables does not need to be changed.
The macro must emit an error, and the error message must contains "no path".</p>
</blockquote>
<p>Recall that the <code>//~ ERROR OK</code> is a comment from the point of view of the Rust
code we test, but is meaningful from the point of view of the test itself.</p>
<h2 id="debugging-the-dependency-graph"><a class="header" href="#debugging-the-dependency-graph">Debugging the dependency graph</a></h2>
<h3 id="dumping-the-graph"><a class="header" href="#dumping-the-graph">Dumping the graph</a></h3>
<p>The compiler is also capable of dumping the dependency graph for your
debugging pleasure. To do so, pass the <code>-Z dump-dep-graph</code> flag. The
graph will be dumped to <code>dep_graph.{txt,dot}</code> in the current
directory. You can override the filename with the <code>RUST_DEP_GRAPH</code>
environment variable.</p>
<p>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:</p>
<ol>
<li>All edges originating in a particular set of nodes (usually a single node).</li>
<li>All edges reaching a particular set of nodes.</li>
<li>All edges that lie between given start and end nodes.</li>
</ol>
<p>To filter, use the <code>RUST_DEP_GRAPH_FILTER</code> environment variable, which should
look like one of the following:</p>
<pre><code class="language-text">source_filter // nodes originating from source_filter
-&gt; target_filter // nodes that can reach target_filter
source_filter -&gt; target_filter // nodes in between source_filter and target_filter
</code></pre>
<p><code>source_filter</code> and <code>target_filter</code> are a <code>&amp;</code>-separated list of strings.
A node is considered to match a filter if all of those strings appear in its
label. So, for example:</p>
<pre><code class="language-text">RUST_DEP_GRAPH_FILTER='-&gt; TypeckTables'
</code></pre>
<p>would select the predecessors of all <code>TypeckTables</code> nodes. Usually though you
want the <code>TypeckTables</code> node for some particular fn, so you might write:</p>
<pre><code class="language-text">RUST_DEP_GRAPH_FILTER='-&gt; TypeckTables &amp; bar'
</code></pre>
<p>This will select only the predecessors of <code>TypeckTables</code> nodes for functions
with <code>bar</code> in their name.</p>
<p>Perhaps you are finding that when you change <code>foo</code> you need to re-type-check
<code>bar</code>, but you don't think you should have to. In that case, you might do:</p>
<pre><code class="language-text">RUST_DEP_GRAPH_FILTER='Hir &amp; foo -&gt; TypeckTables &amp; bar'
</code></pre>
<p>This will dump out all the nodes that lead from <code>Hir(foo)</code> to
<code>TypeckTables(bar)</code>, from which you can (hopefully) see the source
of the erroneous edge.</p>
<h3 id="tracking-down-incorrect-edges"><a class="header" href="#tracking-down-incorrect-edges">Tracking down incorrect edges</a></h3>
<p>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. <strong>When the compiler is built with debug assertions,</strong> it can
help you track that down. Simply set the <code>RUST_FORBID_DEP_GRAPH_EDGE</code>
environment variable to a filter. Every edge created in the dep-graph
will be tested against that filter if it matches, a <code>bug!</code> is
reported, so you can easily see the backtrace (<code>RUST_BACKTRACE=1</code>).</p>
<p>The syntax for these filters is the same as described in the previous
section. However, note that this filter is applied to every <strong>edge</strong>
and doesn't handle longer paths in the graph, unlike the previous
section.</p>
<p>Example:</p>
<p>You find that there is a path from the <code>Hir</code> of <code>foo</code> to the type
check of <code>bar</code> and you don't think there should be. You dump the
dep-graph as described in the previous section and open <code>dep-graph.txt</code>
to see something like:</p>
<pre><code class="language-text">Hir(foo) -&gt; Collect(bar)
Collect(bar) -&gt; TypeckTables(bar)
</code></pre>
<p>That first edge looks suspicious to you. So you set
<code>RUST_FORBID_DEP_GRAPH_EDGE</code> to <code>Hir&amp;foo -&gt; Collect&amp;bar</code>, re-run, and
then observe the backtrace. Voila, bug fixed!</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="queries/incremental-compilation-in-detail.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="queries/salsa.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="queries/incremental-compilation-in-detail.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="queries/salsa.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script src="mermaid.min.js"></script>
<script src="mermaid-init.js"></script>
</div>
</body>
</html>