]> git.proxmox.com Git - rustc.git/blob - src/doc/rustc-dev-guide/src/compiler-debugging.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / compiler-debugging.md
1 # Debugging the compiler
2 [debugging]: #debugging
3
4 <!-- toc -->
5
6 This chapter contains a few tips to debug the compiler. These tips aim to be
7 useful no matter what you are working on. Some of the other chapters have
8 advice about specific parts of the compiler (e.g. the [Queries Debugging and
9 Testing chapter](./incrcomp-debugging.html) or the [LLVM Debugging
10 chapter](./backend/debugging.md)).
11
12 ## Configuring the compiler
13
14 By default, rustc is built without most debug information. To enable debug info,
15 set `debug = true` in your config.toml.
16
17 Setting `debug = true` turns on many different debug options (e.g., `debug-assertions`,
18 `debug-logging`, etc.) which can be individually tweaked if you want to, but many people
19 simply set `debug = true`. Check out the comments in config.toml.example for more info.
20
21 You will need to rebuild the compiler once you've changed any configuration options.
22
23 ## `-Z` flags
24
25 The compiler has a bunch of `-Z` flags. These are unstable flags that are only
26 enabled on nightly. Many of them are useful for debugging. To get a full listing
27 of `-Z` flags, use `-Z help`.
28
29 One useful flag is `-Z verbose`, which generally enables printing more info that
30 could be useful for debugging.
31
32 ## Getting a backtrace
33 [getting-a-backtrace]: #getting-a-backtrace
34
35 When you have an ICE (panic in the compiler), you can set
36 `RUST_BACKTRACE=1` to get the stack trace of the `panic!` like in
37 normal Rust programs. IIRC backtraces **don't work** on MinGW,
38 sorry. If you have trouble or the backtraces are full of `unknown`,
39 you might want to find some way to use Linux, Mac, or MSVC on Windows.
40
41 In the default configuration (without `debug` set to `true`), you don't have line numbers
42 enabled, so the backtrace looks like this:
43
44 ```text
45 stack backtrace:
46 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
47 1: std::sys_common::backtrace::_print
48 2: std::panicking::default_hook::{{closure}}
49 3: std::panicking::default_hook
50 4: std::panicking::rust_panic_with_hook
51 5: std::panicking::begin_panic
52 (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~)
53 32: rustc_typeck::check_crate
54 33: <std::thread::local::LocalKey<T>>::with
55 34: <std::thread::local::LocalKey<T>>::with
56 35: rustc::ty::context::TyCtxt::create_and_enter
57 36: rustc_driver::driver::compile_input
58 37: rustc_driver::run_compiler
59 ```
60
61 If you set `debug = true`, you will get line numbers for the stack trace.
62 Then the backtrace will look like this:
63
64 ```text
65 stack backtrace:
66 (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~)
67 at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:110
68 7: rustc_typeck::check::cast::CastCheck::check
69 at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:572
70 at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:460
71 at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:370
72 (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~)
73 33: rustc_driver::driver::compile_input
74 at /home/user/rust/compiler/rustc_driver/src/driver.rs:1010
75 at /home/user/rust/compiler/rustc_driver/src/driver.rs:212
76 34: rustc_driver::run_compiler
77 at /home/user/rust/compiler/rustc_driver/src/lib.rs:253
78 ```
79
80 ## Getting a backtrace for errors
81 [getting-a-backtrace-for-errors]: #getting-a-backtrace-for-errors
82
83 If you want to get a backtrace to the point where the compiler emits an
84 error message, you can pass the `-Z treat-err-as-bug=n`, which will make
85 the compiler panic on the `nth` error on `delay_span_bug`. If you leave
86 off `=n`, the compiler will assume `1` for `n` and thus panic on the
87 first error it encounters.
88
89 This can also help when debugging `delay_span_bug` calls - it will make
90 the first `delay_span_bug` call panic, which will give you a useful backtrace.
91
92 For example:
93
94 ```bash
95 $ cat error.rs
96 ```
97
98 ```rust
99 fn main() {
100 1 + ();
101 }
102 ```
103
104 ```bash
105 $ rustc +stage1 error.rs
106 error[E0277]: cannot add `()` to `{integer}`
107 --> error.rs:2:7
108 |
109 2 | 1 + ();
110 | ^ no implementation for `{integer} + ()`
111 |
112 = help: the trait `Add<()>` is not implemented for `{integer}`
113
114 error: aborting due to previous error
115 ```
116
117 Now, where does the error above come from?
118
119 ```bash
120 $ RUST_BACKTRACE=1 rustc +stage1 error.rs -Z treat-err-as-bug
121 error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied
122 --> error.rs:2:7
123 |
124 2 | 1 + ();
125 | ^ no implementation for `{integer} + ()`
126 |
127 = help: the trait `std::ops::Add<()>` is not implemented for `{integer}`
128
129 error: internal compiler error: unexpected panic
130
131 note: the compiler unexpectedly panicked. this is a bug.
132
133 note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
134
135 note: rustc 1.24.0-dev running on x86_64-unknown-linux-gnu
136
137 note: run with `RUST_BACKTRACE=1` for a backtrace
138
139 thread 'rustc' panicked at 'encountered error with `-Z treat_err_as_bug',
140 /home/user/rust/compiler/rustc_errors/src/lib.rs:411:12
141 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose
142 backtrace.
143 stack backtrace:
144 (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~)
145 7: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'tcx>>
146 ::report_selection_error
147 at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:823
148 8: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'tcx>>
149 ::report_fulfillment_errors
150 at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:160
151 at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:112
152 9: rustc_typeck::check::FnCtxt::select_obligations_where_possible
153 at /home/user/rust/compiler/rustc_typeck/src/check/mod.rs:2192
154 (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~)
155 36: rustc_driver::run_compiler
156 at /home/user/rust/compiler/rustc_driver/src/lib.rs:253
157 ```
158
159 Cool, now I have a backtrace for the error!
160
161 ## Getting logging output
162 [getting-logging-output]: #getting-logging-output
163
164 The compiler uses the [`tracing`] crate for logging.
165
166 [`tracing`]: https://docs.rs/tracing
167
168 The compiler has a lot of [`debug!`] calls, which print out logging information
169 at many points. These are very useful to at least narrow down the location of
170 a bug if not to find it entirely, or just to orient yourself as to why the
171 compiler is doing a particular thing.
172
173 [`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html
174
175 To see the logs, you need to set the `RUSTC_LOG` environment variable to your
176 log filter. Your log filter can be just `debug` to get all `debug!` output and
177 higher (e.g., it will also include `info!`), or `path::to::module` to get *all*
178 output (which will include `trace!`) from a particular module, or
179 `path::to::module=debug` to get `debug!` output and higher from a particular
180 module.
181
182 For example, to get the `debug!` output and higher for a specific module, you
183 can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`.
184 All `debug!` output will then appear in standard error.
185
186 Note that you can use a partial path and the filter will still work. For
187 example, if you want to see `info!` output from only
188 `rustdoc::passes::collect_intra_doc_links`, you could use
189 `RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use
190 `RUSTDOC_LOG=rustdoc::passes::collect_intra=info`.
191
192 If you are developing rustdoc, use `RUSTDOC_LOG` instead. If you are developing
193 Miri, use `MIRI_LOG` instead. You get the idea :)
194
195 See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to
196 see the full syntax you can use. (Note: unlike the compiler, the [`tracing`]
197 crate and its examples use the `RUST_LOG` environment variable. rustc, rustdoc,
198 and other tools set custom environment variables.)
199
200 **Note that unless you use a very strict filter, the logger will emit a lot of
201 output, so use the most specific module(s) you can (comma-separated if
202 multiple)**. It's typically a good idea to pipe standard error to a file and
203 look at the log output with a text editor.
204
205 So, to put it together:
206
207 ```bash
208 # This puts the output of all debug calls in `rustc_middle/src/traits` into
209 # standard error, which might fill your console backscroll.
210 $ RUSTC_LOG=rustc_middle::traits=debug rustc +stage1 my-file.rs
211
212 # This puts the output of all debug calls in `rustc_middle/src/traits` in
213 # `traits-log`, so you can then see it with a text editor.
214 $ RUSTC_LOG=rustc_middle::traits=debug rustc +stage1 my-file.rs 2>traits-log
215
216 # Not recommended! This will show the output of all `debug!` calls
217 # in the Rust compiler, and there are a *lot* of them, so it will be
218 # hard to find anything.
219 $ RUSTC_LOG=debug rustc +stage1 my-file.rs 2>all-log
220
221 # This will show the output of all `info!` calls in `rustc_codegen_ssa`.
222 #
223 # There's an `info!` statement in `codegen_instance` that outputs
224 # every function that is codegen'd. This is useful to find out
225 # which function triggers an LLVM assertion, and this is an `info!`
226 # log rather than a `debug!` log so it will work on the official
227 # compilers.
228 $ RUSTC_LOG=rustc_codegen_ssa=info rustc +stage1 my-file.rs
229
230 # This will show the output of all `info!` calls made by rustdoc
231 # or any rustc library it calls.
232 $ RUSTDOC_LOG=info rustdoc +stage1 my-file.rs
233
234 # This will only show `debug!` calls made by rustdoc directly,
235 # not any `rustc*` crate.
236 $ RUSTDOC_LOG=rustdoc=debug rustdoc +stage1 my-file.rs
237 ```
238
239 ### Log colors
240
241 By default, rustc (and other tools, like rustdoc and Miri) will be smart about
242 when to use ANSI colors in the log output. If they are outputting to a terminal,
243 they will use colors, and if they are outputting to a file or being piped
244 somewhere else, they will not. However, it's hard to read log output in your
245 terminal unless you have a very strict filter, so you may want to pipe the
246 output to a pager like `less`. But then there won't be any colors, which makes
247 it hard to pick out what you're looking for!
248
249 You can override whether to have colors in log output with the `RUSTC_LOG_COLOR`
250 environment variable (or `RUSTDOC_LOG_COLOR` for rustdoc, or `MIRI_LOG_COLOR`
251 for Miri, etc.). There are three options: `auto` (the default), `always`, and
252 `never`. So, if you want to enable colors when piping to `less`, use something
253 similar to this command:
254
255 ```bash
256 # The `-R` switch tells less to print ANSI colors without escaping them.
257 $ RUSTC_LOG=debug RUSTC_LOG_COLOR=always rustc +stage1 ... | less -R
258 ```
259
260 Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, not logs
261 from rustc functions that Miri calls. Use `RUSTC_LOG_COLOR` to color logs from
262 rustc.
263
264 ### How to keep or remove `debug!` and `trace!` calls from the resulting binary
265
266 While calls to `error!`, `warn!` and `info!` are included in every build of the compiler,
267 calls to `debug!` and `trace!` are only included in the program if
268 `debug-logging=true` is turned on in config.toml (it is
269 turned off by default), so if you don't see `DEBUG` logs, especially
270 if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see
271 `INFO` logs, make sure that `debug-logging=true` is turned on in your
272 config.toml.
273
274 ### Logging etiquette and conventions
275
276 Because calls to `debug!` are removed by default, in most cases, don't worry
277 about adding "unnecessary" calls to `debug!` and leaving them in code you
278 commit - they won't slow down the performance of what we ship, and if they
279 helped you pinning down a bug, they will probably help someone else with a
280 different one.
281
282 A loosely followed convention is to use `debug!("foo(...)")` at the _start_ of
283 a function `foo` and `debug!("foo: ...")` _within_ the function. Another
284 loosely followed convention is to use the `{:?}` format specifier for debug
285 logs.
286
287 One thing to be **careful** of is **expensive** operations in logs.
288
289 If in the module `rustc::foo` you have a statement
290
291 ```Rust
292 debug!("{:?}", random_operation(tcx));
293 ```
294
295 Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::bar`, then
296 `random_operation()` will run.
297
298 This means that you should not put anything too expensive or likely to crash
299 there - that would annoy anyone who wants to use logging for their own module.
300 No-one will know it until someone tries to use logging to find *another* bug.
301
302 ## Formatting Graphviz output (.dot files)
303 [formatting-graphviz-output]: #formatting-graphviz-output
304
305 Some compiler options for debugging specific features yield graphviz graphs -
306 e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute
307 dumps various borrow-checker dataflow graphs.
308
309 These all produce `.dot` files. To view these files, install graphviz (e.g.
310 `apt-get install graphviz`) and then run the following commands:
311
312 ```bash
313 $ dot -T pdf maybe_init_suffix.dot > maybe_init_suffix.pdf
314 $ firefox maybe_init_suffix.pdf # Or your favorite pdf viewer
315 ```
316
317 ## Viewing Spanview output (.html files)
318 [viewing-spanview-output]: #viewing-spanview-output
319
320 In addition to [graphviz output](#formatting-graphviz-output-dot-files), MIR debugging
321 flags include an option to generate a MIR representation called `Spanview` that
322 uses HTML to highlight code regions in the original source code and display
323 compiler metadata associated with each region.
324 [`-Z dump-mir-spanview`](./mir/debugging.md), for example, highlights spans
325 associated with each MIR `Statement`, `Terminator`, and/or `BasicBlock`.
326
327 These `.html` files use CSS features to dynamically expand spans obscured by
328 overlapping spans, and native tooltips (based on the HTML `title` attribute) to
329 reveal the actual MIR elements, as text.
330
331 To view these files, simply use a modern browser, or a CSS-capable HTML preview
332 feature in a modern IDE. (The default HTML preview pane in *VS Code* is known to
333 work, for instance.)
334
335 ## Narrowing (Bisecting) Regressions
336
337 The [cargo-bisect-rustc][bisect] tool can be used as a quick and easy way to
338 find exactly which PR caused a change in `rustc` behavior. It automatically
339 downloads `rustc` PR artifacts and tests them against a project you provide
340 until it finds the regression. You can then look at the PR to get more context
341 on *why* it was changed. See [this tutorial][bisect-tutorial] on how to use
342 it.
343
344 [bisect]: https://github.com/rust-lang/cargo-bisect-rustc
345 [bisect-tutorial]: https://github.com/rust-lang/cargo-bisect-rustc/blob/master/TUTORIAL.md
346
347 ## Downloading Artifacts from Rust's CI
348
349 The [rustup-toolchain-install-master][rtim] tool by kennytm can be used to
350 download the artifacts produced by Rust's CI for a specific SHA1 -- this
351 basically corresponds to the successful landing of some PR -- and then sets
352 them up for your local use. This also works for artifacts produced by `@bors
353 try`. This is helpful when you want to examine the resulting build of a PR
354 without doing the build yourself.
355
356 [rtim]: https://github.com/kennytm/rustup-toolchain-install-master
357
358 ## Debugging type layouts
359
360 The (permanently) unstable `#[rustc_layout]` attribute can be used to dump
361 the [`Layout`] of the type it is attached to. For example:
362
363 ```rust
364 #![feature(rustc_attrs)]
365
366 #[rustc_layout(debug)]
367 type T<'a> = &'a u32;
368 ```
369
370 Will emit the following:
371
372 ```text
373 error: layout_of(&'a u32) = Layout {
374 fields: Primitive,
375 variants: Single {
376 index: 0,
377 },
378 abi: Scalar(
379 Scalar {
380 value: Pointer,
381 valid_range: 1..=18446744073709551615,
382 },
383 ),
384 largest_niche: Some(
385 Niche {
386 offset: Size {
387 raw: 0,
388 },
389 scalar: Scalar {
390 value: Pointer,
391 valid_range: 1..=18446744073709551615,
392 },
393 },
394 ),
395 align: AbiAndPrefAlign {
396 abi: Align {
397 pow2: 3,
398 },
399 pref: Align {
400 pow2: 3,
401 },
402 },
403 size: Size {
404 raw: 8,
405 },
406 }
407 --> src/lib.rs:4:1
408 |
409 4 | type T<'a> = &'a u32;
410 | ^^^^^^^^^^^^^^^^^^^^^
411
412 error: aborting due to previous error
413 ```
414
415 [`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/abi/struct.Layout.html