]> git.proxmox.com Git - rustc.git/blobdiff - src/doc/rustc-guide/src/compiler-debugging.md
New upstream version 1.41.1+dfsg1
[rustc.git] / src / doc / rustc-guide / src / compiler-debugging.md
index aca7f7424b8c91c50915c6c69bda802d55f6bc8c..736de9771283a3f9eaaa482224e12f395112430f 100644 (file)
@@ -1,20 +1,30 @@
-**Note: This is copied from the
-[rust-forge](https://github.com/rust-lang-nursery/rust-forge). If anything needs
- updating, please open an issue or make a PR on the github repo.**
-
 # Debugging the compiler
 [debugging]: #debugging
 
-Here are a few tips to debug the compiler:
+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.html) or
+the [LLVM Debugging chapter](./codegen/debugging.md)).
+
+## `-Z` flags
+
+The compiler has a bunch of `-Z` flags. These are unstable flags that are only
+enabled on nightly. Many of them are useful for debugging. To get a full listing
+of `-Z` flags, use `-Z help`.
+
+One useful flag is `-Z verbose`, which generally enables printing more info that
+could be useful for debugging.
 
 ## Getting a backtrace
 [getting-a-backtrace]: #getting-a-backtrace
 
 When you have an ICE (panic in the compiler), you can set
 `RUST_BACKTRACE=1` to get the stack trace of the `panic!` like in
-normal Rust programs.  IIRC backtraces **don't work** on Mac and on MinGW,
+normal Rust programs.  IIRC backtraces **don't work** on MinGW,
 sorry. If you have trouble or the backtraces are full of `unknown`,
-you might want to find some way to use Linux or MSVC on Windows.
+you might want to find some way to use Linux, Mac, or MSVC on Windows.
 
 In the default configuration, you don't have line numbers enabled, so the
 backtrace looks like this:
@@ -36,9 +46,10 @@ stack backtrace:
   37: rustc_driver::run_compiler
 ```
 
-If you want line numbers for the stack trace, you can enable
-`debuginfo-lines=true` or `debuginfo=true` in your config.toml and rebuild the
-compiler. Then the backtrace will look like this:
+If you want line numbers for the stack trace, you can enable `debug = true` in
+your config.toml and rebuild the compiler (`debuginfo-level = 1` will also add
+line numbers, but `debug = true` gives full debuginfo). Then the backtrace will
+look like this:
 
 ```text
 stack backtrace:
@@ -60,8 +71,10 @@ stack backtrace:
 [getting-a-backtrace-for-errors]: #getting-a-backtrace-for-errors
 
 If you want to get a backtrace to the point where the compiler emits
-an error message, you can pass the `-Z treat-err-as-bug`, which
-will make the compiler panic on the first error it sees.
+an error message, you can pass the `-Z treat-err-as-bug=n`, which
+will make the compiler skip `n` errors or `delay_span_bug` calls and then
+panic on the next one. If you leave off `=n`, the compiler will assume `0` for
+`n` and thus panic on the first error it encounters.
 
 This can also help when debugging `delay_span_bug` calls - it will make
 the first `delay_span_bug` call panic, which will give you a useful backtrace.
@@ -116,11 +129,11 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose
 backtrace.
 stack backtrace:
   (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~)
-   7: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'gcx,
-             'tcx>>::report_selection_error
+   7: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'tcx>>
+             ::report_selection_error
              at /home/user/rust/src/librustc/traits/error_reporting.rs:823
-   8: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'gcx,
-             'tcx>>::report_fulfillment_errors
+   8: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'tcx>>
+             ::report_fulfillment_errors
              at /home/user/rust/src/librustc/traits/error_reporting.rs:160
              at /home/user/rust/src/librustc/traits/error_reporting.rs:112
    9: rustc_typeck::check::FnCtxt::select_obligations_where_possible
@@ -134,37 +147,44 @@ $ # Cool, now I have a backtrace for the error
 ## Getting logging output
 [getting-logging-output]: #getting-logging-output
 
+These crates are used in compiler for logging:
+
+* [log]
+* [env-logger]: check the link to see the full `RUSTC_LOG` syntax
+
+[log]: https://docs.rs/log/0.4.6/log/index.html
+[env-logger]: https://docs.rs/env_logger/0.4.3/env_logger/
+
 The compiler has a lot of `debug!` calls, which print out logging information
 at many points. These are very useful to at least narrow down the location of
 a bug if not to find it entirely, or just to orient yourself as to why the
 compiler is doing a particular thing.
 
-To see the logs, you need to set the `RUST_LOG` environment variable to
+To see the logs, you need to set the `RUSTC_LOG` environment variable to
 your log filter, e.g. to get the logs for a specific module, you can run the
-compiler as `RUST_LOG=module::path rustc my-file.rs`. The Rust logs are
-powered by [env-logger], and you can look at the docs linked there to see
-the full `RUST_LOG` syntax. All `debug!` output will then appear in
-standard error.
+compiler as `RUSTC_LOG=module::path rustc my-file.rs`. All `debug!` output will
+then appear in standard error.
 
-Note that unless you use a very strict filter, the logger will emit a *lot*
-of output - so it's typically a good idea to pipe standard error to a file
-and look at the log output with a text editor.
+**Note that unless you use a very strict filter, the logger will emit a lot of
+output, so use the most specific module(s) you can (comma-separated if
+multiple)**. It's typically a good idea to pipe standard error to a file and
+look at the log output with a text editor.
 
 So to put it together.
 
 ```bash
 # This puts the output of all debug calls in `librustc/traits` into
 # standard error, which might fill your console backscroll.
-$ RUST_LOG=rustc::traits rustc +local my-file.rs
+$ RUSTC_LOG=rustc::traits rustc +local my-file.rs
 
 # This puts the output of all debug calls in `librustc/traits` in
 # `traits-log`, so you can then see it with a text editor.
-$ RUST_LOG=rustc::traits rustc +local my-file.rs 2>traits-log
+$ RUSTC_LOG=rustc::traits rustc +local my-file.rs 2>traits-log
 
 # Not recommended. This will show the output of all `debug!` calls
 # in the Rust compiler, and there are a *lot* of them, so it will be
 # hard to find anything.
-$ RUST_LOG=debug rustc +local my-file.rs 2>all-log
+$ RUSTC_LOG=debug rustc +local my-file.rs 2>all-log
 
 # This will show the output of all `info!` calls in `rustc_trans`.
 #
@@ -173,14 +193,16 @@ $ RUST_LOG=debug rustc +local my-file.rs 2>all-log
 # which function triggers an LLVM assertion, and this is an `info!`
 # log rather than a `debug!` log so it will work on the official
 # compilers.
-$ RUST_LOG=rustc_trans=info rustc +local my-file.rs
+$ RUSTC_LOG=rustc_trans=info rustc +local my-file.rs
 ```
 
-While calls to `info!` are included in every build of the compiler,
-calls to `debug!` are only included in the program if the
+### How to keep or remove `debug!` and `trace!` calls from the resulting binary
+
+While calls to `error!`, `warn!` and `info!` are included in every build of the compiler,
+calls to `debug!` and `trace!` are only included in the program if
 `debug-assertions=yes` is turned on in config.toml (it is
 turned off by default), so if you don't see `DEBUG` logs, especially
-if you run the compiler with `RUST_LOG=rustc rustc some.rs` and only see
+if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see
 `INFO` logs, make sure that `debug-assertions=yes` is turned on in your
 config.toml.
 
@@ -188,7 +210,7 @@ I also think that in some cases just setting it will not trigger a rebuild,
 so if you changed it and you already have a compiler built, you might
 want to call `x.py clean` to force one.
 
-### Logging etiquette
+### Logging etiquette and conventions
 
 Because calls to `debug!` are removed by default, in most cases, don't worry
 about adding "unnecessary" calls to `debug!` and leaving them in code you
@@ -196,52 +218,25 @@ commit - they won't slow down the performance of what we ship, and if they
 helped you pinning down a bug, they will probably help someone else with a
 different one.
 
-However, there are still a few concerns that you might care about:
+A loosely followed convention is to use `debug!("foo(...)")` at the _start_ of
+a function `foo` and `debug!("foo: ...")` _within_ the function. Another
+loosely followed convention is to use the `{:?}` format specifier for debug
+logs.
 
-### Expensive operations in logs
+One thing to be **careful** of is **expensive** operations in logs.
 
-A note of caution: the expressions *within* the `debug!` call are run
-whenever RUST_LOG is set, even if the filter would exclude the log. This means
-that if in the module `rustc::foo` you have a statement
+If in the module `rustc::foo` you have a statement
 
 ```Rust
 debug!("{:?}", random_operation(tcx));
 ```
 
-Then if someone runs a debug `rustc` with `RUST_LOG=rustc::bar`, then
-`random_operation()` will still run - even while it's output will never be
-needed!
-
-This means that you should not put anything too expensive or likely
-to crash there - that would annoy anyone who wants to use logging for their own
-module. Note that if `RUST_LOG` is unset (the default), then the code will not
-run - this means that if your logging code panics, then no-one will know it
-until someone tries to use logging to find *another* bug.
+Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::bar`, then
+`random_operation()` will run.
 
-If you *need* to do an expensive operation in a log, be aware that while log
-expressions are *evaluated* even if logging is not enabled in your module,
-they are not *formatted* unless it *is*. This means you can put your
-expensive/crashy operations inside an `fmt::Debug` impl, and they will not be
-run unless your log is enabled:
-
-```Rust
-use std::fmt;
-
-struct ExpensiveOperationContainer<'a, 'gcx, 'tcx>
-    where 'tcx: 'gcx, 'a: 'tcx
-{
-    tcx: TyCtxt<'a, 'gcx, 'tcx>
-}
-
-impl<'a, 'gcx, 'tcx> fmt::Debug for ExpensiveOperationContainer<'a, 'gcx, 'tcx> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let value = random_operation(tcx);
-        fmt::Debug::fmt(&value, fmt)
-    }
-}
-
-debug!("{:?}", ExpensiveOperationContainer { tcx });
-```
+This means that you should not put anything too expensive or likely to crash
+there - that would annoy anyone who wants to use logging for their own module.
+No-one will know it until someone tries to use logging to find *another* bug.
 
 ## Formatting Graphviz output (.dot files)
 [formatting-graphviz-output]: #formatting-graphviz-output
@@ -258,133 +253,25 @@ $ dot -T pdf maybe_init_suffix.dot > maybe_init_suffix.pdf
 $ firefox maybe_init_suffix.pdf # Or your favorite pdf viewer
 ```
 
-## Debugging LLVM
-[debugging-llvm]: #debugging-llvm
-
-> NOTE: If you are looking for info about code generation, please see [this
-> chapter][codegen] instead.
-
-[codegen]: codegen.html
-
-This section is about debugging compiler bugs in code generation (e.g. why the
-compiler generated some piece of code or crashed in LLVM).  LLVM is a big
-project on its own that probably needs to have its own debugging document (not
-that I could find one). But here are some tips that are important in a rustc
-context:
-
-As a general rule, compilers generate lots of information from analyzing code.
-Thus, a useful first step is usually to find a minimal example. One way to do
-this is to
-
-1. create a new crate that reproduces the issue (e.g. adding whatever crate is
-at fault as a dependency, and using it from there)
-
-2. minimize the crate by removing external dependencies; that is, moving
-everything relevant to the new crate
-
-3. further minimize the issue by making the code shorter (there are tools that
-help with this like `creduce`)
-
-The official compilers (including nightlies) have LLVM assertions disabled,
-which means that LLVM assertion failures can show up as compiler crashes (not
-ICEs but "real" crashes) and other sorts of weird behavior. If you are
-encountering these, it is a good idea to try using a compiler with LLVM
-assertions enabled - either an "alt" nightly or a compiler you build yourself
-by setting `[llvm] assertions=true` in your config.toml - and see whether
-anything turns up.
-
-The rustc build process builds the LLVM tools into
-`./build/<host-triple>/llvm/bin`. They can be called directly.
-
-The default rustc compilation pipeline has multiple codegen units, which is
-hard to replicate manually and means that LLVM is called multiple times in
-parallel.  If you can get away with it (i.e. if it doesn't make your bug
-disappear), passing `-C codegen-units=1` to rustc will make debugging easier.
-
-To rustc to generate LLVM IR, you need to pass the `--emit=llvm-ir` flag. If
-you are building via cargo, use the `RUSTFLAGS` environment variable (e.g.
-`RUSTFLAGS='--emit=llvm-ir'`). This causes rustc to spit out LLVM IR into the
-target directory.
-
-`cargo llvm-ir [options] path` spits out the LLVM IR for a particular function
-at `path`. (`cargo install cargo-asm` installs `cargo asm` and `cargo
-llvm-ir`). `--build-type=debug` emits code for debug builds. There are also
-other useful options. Also, debug info in LLVM IR can clutter the output a lot:
-`RUSTFLAGS="-C debuginfo=0"` is really useful.
-
-`RUSTFLAGS="-C save-temps"` outputs LLVM bitcode (not the same as IR) at
-different stages during compilation, which is sometimes useful. One just needs
-to convert the bitcode files to `.ll` files using `llvm-dis` which should be in
-the target local compilation of rustc.
-
-If you want to play with the optimization pipeline, you can use the `opt` tool
-from `./build/<host-triple>/llvm/bin/` with the LLVM IR emitted by rustc.  Note
-that rustc emits different IR depending on whether `-O` is enabled, even
-without LLVM's optimizations, so if you want to play with the IR rustc emits,
-you should:
-
-```bash
-$ rustc +local my-file.rs --emit=llvm-ir -O -C no-prepopulate-passes \
-    -C codegen-units=1
-$ OPT=./build/$TRIPLE/llvm/bin/opt
-$ $OPT -S -O2 < my-file.ll > my
-```
-
-If you just want to get the LLVM IR during the LLVM pipeline, to e.g. see which
-IR causes an optimization-time assertion to fail, or to see when LLVM performs
-a particular optimization, you can pass the rustc flag `-C
-llvm-args=-print-after-all`, and possibly add `-C
-llvm-args='-filter-print-funcs=EXACT_FUNCTION_NAME` (e.g.  `-C
-llvm-args='-filter-print-funcs=_ZN11collections3str21_$LT$impl$u20$str$GT$\
-7replace17hbe10ea2e7c809b0bE'`).
-
-That produces a lot of output into standard error, so you'll want to pipe that
-to some file. Also, if you are using neither `-filter-print-funcs` nor `-C
-codegen-units=1`, then, because the multiple codegen units run in parallel, the
-printouts will mix together and you won't be able to read anything.
-
-If you want just the IR for a specific function (say, you want to see why it
-causes an assertion or doesn't optimize correctly), you can use `llvm-extract`,
-e.g.
-
-```bash
-$ ./build/$TRIPLE/llvm/bin/llvm-extract \
-    -func='_ZN11collections3str21_$LT$impl$u20$str$GT$7replace17hbe10ea2e7c809b0bE' \
-    -S \
-    < unextracted.ll \
-    > extracted.ll
-```
-
-### Filing LLVM bug reports
-
-When filing an LLVM bug report, you will probably want some sort of minimal
-working example that demonstrates the problem. The Godbolt compiler explorer is
-really helpful for this.
-
-1. Once you have some LLVM IR for the problematic code (see above), you can
-create a minimal working example with Godbolt. Go to
-[gcc.godbolt.org](https://gcc.godbolt.org).
-
-2. Choose `LLVM-IR` as programming language.
-
-3. Use `llc` to compile the IR to a particular target as is:
-    - There are some useful flags: `-mattr` enables target features, `-march=`
-      selects the target, `-mcpu=` selects the CPU, etc.
-    - Commands like `llc -march=help` output all architectures available, which
-      is useful because sometimes the Rust arch names and the LLVM names do not
-      match.
-    - If you have compiled rustc yourself somewhere, in the target directory
-      you have binaries for `llc`, `opt`, etc.
-
-4. If you want to optimize the LLVM-IR, you can use `opt` to see how the LLVM
-   optimizations transform it.
+## Narrowing (Bisecting) Regressions
 
-5. Once you have a godbolt link demonstrating the issue, it is pretty easy to
-   fill in an LLVM bug.
+The [cargo-bisect-rustc][bisect] tool can be used as a quick and easy way to
+find exactly which PR caused a change in `rustc` behavior. It automatically
+downloads `rustc` PR artifacts and tests them against a project you provide
+until it finds the regression. You can then look at the PR to get more context
+on *why* it was changed.  See [this tutorial][bisect-tutorial] on how to use
+it.
 
+[bisect]: https://github.com/rust-lang-nursery/cargo-bisect-rustc
+[bisect-tutorial]: https://github.com/rust-lang-nursery/cargo-bisect-rustc/blob/master/TUTORIAL.md
 
-[env-logger]: https://docs.rs/env_logger/0.4.3/env_logger/
+## Downloading Artifacts from Rust's CI
 
-## Narrowing (Bisecting) Regressions
+The [rustup-toolchain-install-master][rtim] tool by kennytm can be used to
+download the artifacts produced by Rust's CI for a specific SHA1 -- this
+basically corresponds to the successful landing of some PR -- and then sets
+them up for your local use. This also works for artifacts produced by `@bors
+try`. This is helpful when you want to examine the resulting build of a PR
+without doing the build yourself.
 
-The [cargo-bisect-rustc](https://github.com/rust-lang-nursery/cargo-bisect-rustc) tool can be used as a quick and easy way to find exactly which PR caused a change in `rustc` behavior. It automatically downloads `rustc` PR artifacts and tests them against a project you provide until it finds the regression. You can then look at the PR to get more context on *why* it was changed.  See [this tutorial](https://github.com/rust-lang-nursery/cargo-bisect-rustc/blob/master/TUTORIAL.md) on how to use it.
+[rtim]: https://github.com/kennytm/rustup-toolchain-install-master