| # Compiletest | |
| ## Introduction | |
| `compiletest` is the main test harness of the Rust test suite. | |
| It allows test authors to organize large numbers of tests (the Rust compiler has many | |
| thousands), efficient test execution (parallel execution is supported), and | |
| allows the test author to configure behavior and expected results of both | |
| individual and groups of tests. | |
| > **Note for macOS users** | |
| > | |
| > For macOS users, `SIP` (System Integrity Protection) [may consistently check | |
| > the compiled binary by sending network requests to Apple][zulip], so you may | |
| > get a huge performance degradation when running tests. | |
| > | |
| > You can resolve it by tweaking the following settings: `Privacy & Security -> | |
| > Developer Tools -> Add Terminal (Or VsCode, etc.)`. | |
| [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/.E2.9C.94.20Is.20there.20any.20performance.20issue.20for.20MacOS.3F | |
| `compiletest` may check test code for compile-time or run-time success/failure. | |
| Tests are typically organized as a Rust source file with annotations in comments | |
| before and/or within the test code. | |
| These comments serve to direct `compiletest` | |
| on if or how to run the test, what behavior to expect, and more. | |
| See [directives](directives.md) and the test suite documentation below for more details | |
| on these annotations. | |
| See the [Adding new tests](adding.md) and [Best practices](best-practices.md) | |
| chapters for a tutorial on creating a new test and advice on writing a good | |
| test, and the [Running tests](running.md) chapter on how to run the test suite. | |
| Arguments can be passed to compiletest using `--test-args` or by placing them after `--`, e.g. | |
| - `x test --test-args --force-rerun` | |
| - `x test -- --force-rerun` | |
| Additionally, bootstrap accepts several common arguments directly, e.g. | |
| `x test --no-capture --force-rerun --run --pass`. | |
| Compiletest itself tries to avoid running tests when the artifacts that are | |
| involved (mainly the compiler) haven't changed. | |
| You can use `x test --test-args | |
| --force-rerun` to rerun a test even when none of the inputs have changed. | |
| ## Test suites | |
| All of the tests are in the [`tests`] directory. | |
| The tests are organized into "suites", with each suite in a separate subdirectory. | |
| Each test suite behaves a | |
| little differently, with different compiler behavior and different checks for correctness. | |
| For example, the [`tests/incremental`] directory contains tests for incremental compilation. | |
| The various suites are defined in | |
| [`src/tools/compiletest/src/common.rs`] in the `pub enum Mode` declaration. | |
| The following test suites are available, with links for more information: | |
| [`tests`]: https://github.com/rust-lang/rust/blob/HEAD/tests | |
| [`src/tools/compiletest/src/common.rs`]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/compiletest/src/common.rs | |
| ### Compiler-specific test suites | |
| | Test suite | Purpose | | |
| |-------------------------------------------|---------------------------------------------------------------------------------------------------------------------| | |
| | [`ui`](ui.md) | Check the stdout/stderr snapshots from the compilation and/or running the resulting executable | | |
| | `ui-fulldeps` | `ui` tests which require a linkable build of `rustc` (such as using `extern crate rustc_span;` or used as a plugin) | | |
| | [`pretty`](#pretty-printer-tests) | Check pretty printing | | |
| | [`incremental`](#incremental-tests) | Check incremental compilation behavior | | |
| | [`debuginfo`](#debuginfo-tests) | Check debuginfo generation running debuggers | | |
| | [`codegen-*`](#codegen-tests) | Check code generation | | |
| | [`codegen-units`](#codegen-units-tests) | Check codegen unit partitioning | | |
| | [`assembly`](#assembly-tests) | Check assembly output | | |
| | [`mir-opt`](#mir-opt-tests) | Check MIR generation and optimizations | | |
| | [`coverage`](#coverage-tests) | Check coverage instrumentation | | |
| | [`coverage-run-rustdoc`](#coverage-tests) | `coverage` tests that also run instrumented doctests | | |
| | [`crashes`](#crash-tests) | Check that the compiler ICEs/panics/crashes on certain inputs to catch accidental fixes | | |
| ### General purpose test suite | |
| [`run-make`](#run-make-tests) are general purpose tests using Rust programs. | |
| ### The build-std test suite | |
| [`build-std`](#build-std-tests) tests that -Zbuild-std works. | |
| ### Rustdoc test suites | |
| | Test suite | Purpose | | |
| |--------------------------------------|--------------------------------------------------------------------------| | |
| | [`rustdoc-html`][rustdoc-html-tests] | Check HTML output of `rustdoc` | | |
| | [`rustdoc-gui`][rustdoc-gui-tests] | Check `rustdoc`'s GUI using a web browser | | |
| | [`rustdoc-js`][rustdoc-js-tests] | Check `rustdoc`'s search engine and index | | |
| | [`rustdoc-js-std`][rustdoc-js-tests] | Check `rustdoc`'s search engine and index on the std library docs | | |
| | [`rustdoc-json`][rustdoc-json-tests] | Check JSON output of `rustdoc` | | |
| | `rustdoc-ui` | Check terminal output of `rustdoc` ([see also](ui.md)) | | |
| `ui/rustdoc/` also contains some rustdoc-specific tests. | |
| These tests ensure that certain lints that are emitted as part of executing rustdoc | |
| are also run when executing rustc. | |
| `run-make/rustdoc/` contains run-make tests pertaining to rustdoc. | |
| [rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md | |
| [rustdoc-gui-tests]: ../rustdoc-internals/rustdoc-gui-test-suite.md | |
| [rustdoc-js-tests]: ../rustdoc-internals/search.md#testing-the-search-engine | |
| [rustdoc-json-tests]: ../rustdoc-internals/rustdoc-json-test-suite.md | |
| ### Pretty-printer tests | |
| The tests in [`tests/pretty`] exercise the "pretty-printing" functionality of `rustc`. | |
| The `-Z unpretty` CLI option for `rustc` causes it to translate the | |
| input source into various different formats, such as the Rust source after macro expansion. | |
| The pretty-printer tests have several [directives](directives.md) described below. | |
| These commands can significantly change the behavior of the test, but the | |
| default behavior without any commands is to: | |
| 1. Run `rustc -Zunpretty=normal` on the source file. | |
| 2. Run `rustc -Zunpretty=normal` on the output of the previous step. | |
| 3. The output of the previous two steps should be the same. | |
| 4. Run `rustc -Zno-codegen` on the output to make sure that it can type check | |
| (similar to `cargo check`). | |
| If any of the commands above fail, then the test fails. | |
| The directives for pretty-printing tests are: | |
| - `pretty-mode` specifies the mode pretty-print tests should run in (that is, | |
| the argument to `-Zunpretty`). | |
| The default is `normal` if not specified. | |
| - `pretty-compare-only` causes a pretty test to only compare the pretty-printed | |
| output (stopping after step 3 from above). | |
| It will not try to compile the expanded output to type check it. | |
| This is needed for a pretty-mode that does | |
| not expand to valid Rust, or for other situations where the expanded output cannot be compiled. | |
| - `pp-exact` is used to ensure a pretty-print test results in specific output. | |
| If specified without a value, then it means the pretty-print output should | |
| match the original source. | |
| If specified with a value, as in `//@ | |
| pp-exact:foo.pp`, it will ensure that the pretty-printed output matches the | |
| contents of the given file. | |
| Otherwise, if `pp-exact` is not specified, then | |
| the pretty-printed output will be pretty-printed one more time, and the output | |
| of the two pretty-printing rounds will be compared to ensure that the | |
| pretty-printed output converges to a steady state. | |
| [`tests/pretty`]: https://github.com/rust-lang/rust/tree/HEAD/tests/pretty | |
| ### Incremental tests | |
| The tests in [`tests/incremental`] exercise incremental compilation. | |
| They use [`revisions` directive](#revisions) to tell compiletest to run the compiler in a | |
| series of steps. | |
| Compiletest starts with an empty directory with the `-C incremental` flag, and | |
| then runs the compiler for each revision, reusing the incremental results from previous steps. | |
| Each revision name must start with one of: | |
| * `cpass` - the test must compile successfully (check build, no codegen) | |
| * `bfail` — the test must fail to compile (full build, with codegen) | |
| * `bpass` — the test must compile successully (full build, with codegen) | |
| * `rpass` — the test must compile and run successfully | |
| To make the revisions unique, you should add a suffix like `rpass1` and `rpass2`. | |
| To simulate changing the source, compiletest also passes a `--cfg` flag with the | |
| current revision name. | |
| For example, this will run twice, simulating changing a function: | |
| ```rust,ignore | |
| //@ revisions: rpass1 rpass2 | |
| #[cfg(rpass1)] | |
| fn foo() { | |
| println!("one"); | |
| } | |
| #[cfg(rpass2)] | |
| fn foo() { | |
| println!("two"); | |
| } | |
| fn main() { foo(); } | |
| ``` | |
| Incremental tests support the `forbid-output` directive to specify that a certain | |
| substring must not appear anywhere in the compiler output. | |
| This can be useful to ensure certain errors do not appear, but this can be fragile as error messages | |
| change over time, and a test may no longer be checking the right thing but will still pass. | |
| Incremental tests may use the attribute `#[rustc_clean(...)]` attribute. | |
| This attribute compares the fingerprint from the current compilation session with the previous one. | |
| The first revision should never have an active `rustc_clean` attribute, since it will always be dirty. | |
| In the default mode, it asserts that the fingerprints must be the same. | |
| The attribute takes the following arguments: | |
| * `cfg="<cond>"` — checks the cfg condition `<cond>`, and only runs the check if the config condition evaluates to true. | |
| This can be used to only run the `rustc_clean` attribute in a specific revision. | |
| * `except="<query1>,<query2>,..."` — asserts that the query results for the listed queries must be different, | |
| rather than the same. | |
| * `loaded_from_disk="<query1>,<query2>,..."` — asserts that the query results for the listed queries | |
| were actually loaded from disk (not just marked green). | |
| This can be useful to ensure that a test is actually exercising the deserialization | |
| logic for a particular query result. | |
| This can be combined with `except`. | |
| A simple example of a test using `rustc_clean` is the [hello_world test]. | |
| [`tests/incremental`]: https://github.com/rust-lang/rust/tree/7b42543/tests/incremental | |
| [hello_world test]: https://github.com/rust-lang/rust/blob/646a3f8c15baefb98dc6e0c1c1ba3356db702d2a/tests/incremental/hello_world.rs | |
| ### Debuginfo tests | |
| >[!IMPORTANT] | |
| > As of [#159455](https://github.com/rust-lang/rust/pull/159455) These tests were made | |
| > opt-in. For further context, see: | |
| > [Stabilizing the state of the debuginfo test suite](https://github.com/rust-lang/compiler-team/issues/1012) | |
| The tests in [`tests/debuginfo`] test how debuginfo is interpreted by the supported debuggers, and | |
| confirm our visualizers still work as expected. They build a program, launch a debugger, and issue | |
| commands to the debugger. A single test can work with cdb, gdb, and lldb. | |
| Most tests should have the `//@ compile-flags: -g` directive or something | |
| similar to generate the appropriate debuginfo. | |
| To set a breakpoint on a line, add a `// #break` comment on the line. | |
| The debuginfo tests consist of a series of debugger commands along with | |
| "check" lines which specify output that is expected from the debugger. | |
| The commands are comments of the form `//@ $DEBUGGER-command:$COMMAND` where | |
| `$DEBUGGER` is the debugger being used and `$COMMAND` is the debugger command to execute. | |
| The debugger values can be: | |
| - `cdb` | |
| - `gdb` | |
| - `lldb` | |
| The command to check the output are of the form `//@ $DEBUGGER-check:$OUTPUT` | |
| where `$OUTPUT` is the output to expect. | |
| For example, the following will build the test, start the debugger, set a | |
| breakpoint, launch the program, inspect a value, and check what the debugger prints: | |
| ```rust,ignore | |
| //@ compile-flags: -g | |
| //@ lldb-command: run | |
| //@ lldb-command: print foo | |
| //@ lldb-check: $0 = 123 | |
| fn main() { | |
| let foo = 123; | |
| b(); // #break | |
| } | |
| fn b() {} | |
| ``` | |
| Additionally, there is a special command, `//@ $DEBUGGER-repr:$VAR_NAME` intended to verify | |
| variables (and their visualizers) with more granularity than can be achieved with simple string | |
| comparison. This directive should be preferred over the `-command`/`-check` whenever possible. | |
| > [!NOTE] | |
| > At time of writing (July 2026) this command is limited to LLDB, with an implementation coming soon | |
| > for GDB. There are not firm plans to port the logic to CDB. | |
| This command effectivly desugars into: | |
| ``` | |
| //@ $DEBUGGER-command:repr $VAR_NAME | |
| //@ $DEBUGGER-check:$VAR_NAME ok | |
| ``` | |
| The `repr $VAR_NAME` command is intercepted by special logic that uses the debuggers' API to inspect | |
| data that isn't reflected in the variable's printed output. The variable in memory is compared | |
| against input data stored in | |
| `tests/debuginfo/<test_name>/input/<debugger>_input/<target_group>.json` and | |
| provides detailed error messages on failure. | |
| > [!IMPORTANT] | |
| > `-repr` directives **are** compatible with the `--bless` option, unlike `-command`/`-check`. | |
| > `--bless`-ing a file with `-repr` commands will automatically create/update the appropriate | |
| > target's input data file. | |
| The implementation details of this command are further described in | |
| [the Testing section of the Debug Info chapter](../debuginfo/testing.md). | |
| The following [directives](directives.md) are available to disable a test based on | |
| the debugger currently being used: | |
| - `min-cdb-version: 10.0.18317.1001` — ignores the test if the version of cdb | |
| is below the given version | |
| - `min-gdb-version: 8.2` — ignores the test if the version of gdb is below the given version | |
| - `ignore-gdb-version: 9.2` — ignores the test if the version of gdb is equal | |
| to the given version | |
| - `ignore-gdb-version: 7.11.90 - 8.0.9` — ignores the test if the version of | |
| gdb is in a range (inclusive) | |
| - `min-apple-lldb-version: 1703.0.236.21`/`min-llvm-lldb-version: 21.1.0` — ignores the test if the | |
| version of lldb is below the given version. | |
| Note: Apple's fork of LLDB (distributed with Xcode) uses a different versioning scheme that is not | |
| easily mappable to LLVM's LLDB version numbers. As such, the version gates are specified by | |
| vendor. Further info on manually checking version equivalence is available [here](../debuginfo/testing.md#lldb-versioning) | |
| - `rust-lldb` — ignores the test if lldb is not contain the Rust plugin. | |
| NOTE: The "Rust" version of LLDB doesn't exist anymore, so this will always be ignored. | |
| This should probably be removed. | |
| By passing the `--debugger` option to compiletest, you can specify a single debugger to run tests with. | |
| For example, `./x test tests/debuginfo -- --debugger gdb` will only test GDB commands. | |
| > **Note on running lldb debuginfo tests locally with a prebuilt lldb | |
| > distribution** | |
| > | |
| > If you want to run lldb debuginfo tests locally, then currently on Windows it | |
| > is required that: | |
| > | |
| > # LLDB 21 | |
| > | |
| > - You have Python 3.10 installed. | |
| > - You have `python310.dll` available in your `PATH` env var. This is not | |
| > provided by the standard Python installer you obtain from `python.org`; you | |
| > need to add this to `PATH` manually. | |
| > | |
| > # LLDB 22 | |
| > | |
| > - You have Python 3.11 installed. | |
| > - You have `python311.dll` available in your `PATH`. | |
| > - It is recommended that you acquire a Python installation via `pymanager`, | |
| > which has follow-up installer scripts to help you configure `PATH`. | |
| > | |
| > Otherwise the lldb debuginfo tests can produce crashes in mysterious ways. | |
| [`tests/debuginfo`]: https://github.com/rust-lang/rust/tree/HEAD/tests/debuginfo | |
| > **Note on acquiring `cdb.exe` on Windows 11** | |
| > | |
| > `cdb.exe` is acquired alongside a suitable "Windows 11 SDK" which is part of | |
| > the "Desktop Development with C++" workload profile in a Visual Studio | |
| > installer (e.g. Visual Studio 2022 installer). | |
| > | |
| > **HOWEVER** this is not sufficient by default alone. If you need `cdb.exe`, | |
| > you must go to Installed Apps, find the newest "Windows Software Development | |
| > Kit" (and yes, this can still say `Windows 10.0.22161.3233` even though the OS | |
| > is called Windows 11). You must then click "Modify" -> "Change" and then | |
| > selected "Debugging Tools for Windows" in order to acquire `cdb.exe`. | |
| ### Codegen tests | |
| The tests in [`tests/codegen-llvm`] test LLVM code generation. | |
| They compile the test with the `--emit=llvm-ir` flag to emit LLVM IR. | |
| They then run the LLVM [FileCheck] tool. | |
| The test is annotated with various `// CHECK` comments to check the generated code. | |
| See the [FileCheck] documentation for a tutorial and more information. | |
| See also the [assembly tests](#assembly-tests) for a similar set of tests. | |
| By default, codegen tests will have `//@ needs-target-std` *implied* (that the | |
| target needs to support std), *unless* the `#![no_std]`/`#![no_core]` attribute | |
| was specified in the test source. | |
| You can override this behavior and explicitly | |
| write `//@ needs-target-std` to only run the test when target supports std, even | |
| if the test is `#![no_std]`/`#![no_core]`. | |
| If you need to work with `#![no_std]` cross-compiling tests, consult the | |
| [`minicore` test auxiliary](./minicore.md) chapter. | |
| [`tests/codegen-llvm`]: https://github.com/rust-lang/rust/tree/HEAD/tests/codegen-llvm | |
| [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html | |
| ### Assembly tests | |
| The tests in [`tests/assembly-llvm`] test LLVM assembly output. | |
| They compile the test with the `--emit asm` flag to emit a `.s` file with the assembly output. | |
| They then run the LLVM [FileCheck] tool. | |
| Each test should be annotated with the `//@ assembly-output:` directive with a | |
| value of either `emit-asm` or `ptx-linker` to indicate the type of assembly output. | |
| Then, they should be annotated with various `// CHECK` comments to check the assembly output. | |
| See the [FileCheck] documentation for a tutorial and more information. | |
| See also the [codegen tests](#codegen-tests) for a similar set of tests. | |
| If you need to work with `#![no_std]` cross-compiling tests, consult the | |
| [`minicore` test auxiliary](./minicore.md) chapter. | |
| [`tests/assembly-llvm`]: https://github.com/rust-lang/rust/tree/HEAD/tests/assembly-llvm | |
| ### Codegen-units tests | |
| The tests in [`tests/codegen-units`] test the | |
| [monomorphization](../backend/monomorph.md) collector and CGU partitioning. | |
| These tests work by running `rustc` with a flag to print the result of the | |
| monomorphization collection pass, i.e., `-Zprint-mono-items`, and then special | |
| annotations in the file are used to compare against that. | |
| Then, the test should be annotated with comments of the form `//~ MONO_ITEM | |
| name` where `name` is the monomorphized string printed by rustc like `fn <u32 as Trait>::foo`. | |
| To check for CGU partitioning, a comment of the form `//~ MONO_ITEM name @@ cgu` | |
| where `cgu` is a space separated list of the CGU names and the linkage information in brackets. | |
| For example: `//~ MONO_ITEM static function::FOO @@ statics[Internal]` | |
| [`tests/codegen-units`]: https://github.com/rust-lang/rust/tree/HEAD/tests/codegen-units | |
| ### Mir-opt tests | |
| The tests in [`tests/mir-opt`] check parts of the generated MIR to make sure it | |
| is generated correctly and is doing the expected optimizations. | |
| Check out the [MIR Optimizations](../mir/optimizations.md) chapter for more. | |
| Compiletest will build the test with several flags to dump the MIR output and | |
| set a baseline for optimizations: | |
| * `-Copt-level=1` | |
| * `-Zdump-mir=all` | |
| * `-Zmir-opt-level=4` | |
| * `-Zvalidate-mir` | |
| * `-Zdump-mir-exclude-pass-number` | |
| The test should be annotated with `// EMIT_MIR` comments that specify files that | |
| will contain the expected MIR output. | |
| You can use `x test --bless` to create the initial expected files. | |
| There are several forms the `EMIT_MIR` comment can take: | |
| - `// EMIT_MIR $MIR_PATH.mir` — This will check that the given filename matches | |
| the exact output from the MIR dump. | |
| For example, | |
| `my_test.main.SimplifyCfg-elaborate-drops.after.mir` will load that file from | |
| the test directory, and compare it against the dump from rustc. | |
| Checking the "after" file (which is after optimization) is useful if you are | |
| interested in the final state after an optimization. | |
| Some rare cases may want to use the "before" file for completeness. | |
| - `// EMIT_MIR $MIR_PATH.diff` — where `$MIR_PATH` is the filename of the MIR | |
| dump, such as `my_test_name.my_function.EarlyOtherwiseBranch`. | |
| Compiletest will diff the `.before.mir` and `.after.mir` files, and compare the diff | |
| output to the expected `.diff` file from the `EMIT_MIR` comment. | |
| This is useful if you want to see how an optimization changes the MIR. | |
| - `// EMIT_MIR $MIR_PATH.dot` — When using specific flags that dump additional | |
| MIR data (e.g. `-Z dump-mir-graphviz` to produce `.dot` files), this will | |
| check that the output matches the given file. | |
| By default 32 bit and 64 bit targets use the same dump files, which can be | |
| problematic in the presence of pointers in constants or other bit width dependent things. | |
| In that case you can add `// EMIT_MIR_FOR_EACH_BIT_WIDTH` to | |
| your test, causing separate files to be generated for 32bit and 64bit systems. | |
| [`tests/mir-opt`]: https://github.com/rust-lang/rust/tree/HEAD/tests/mir-opt | |
| ### `run-make` tests | |
| The tests in [`tests/run-make`] and [`tests/run-make-cargo`] are general-purpose | |
| tests using Rust *recipes*, which are small programs (`rmake.rs`) allowing | |
| arbitrary Rust code such as `rustc` invocations, and is supported by a [`run_make_support`] library. | |
| Using Rust recipes provide the ultimate in flexibility. | |
| `run-make` tests should be used if no other test suites better suit your needs. | |
| The `run-make-cargo` test suite additionally builds an in-tree `cargo` to support | |
| use cases that require testing in-tree `cargo` in conjunction with in-tree `rustc`. | |
| The `run-make` test suite does not have access to in-tree `cargo` (so it can be the | |
| faster-to-iterate test suite). | |
| ### `build-std` tests | |
| The tests in [`tests/build-std`] check that `-Zbuild-std` works. | |
| This is currently just a run-make test suite with a single recipe. | |
| The recipe generates test cases and runs them in parallel. | |
| [`tests/build-std`]: https://github.com/rust-lang/rust/tree/HEAD/tests/build-std | |
| #### Using Rust recipes | |
| Each test should be in a separate directory with a `rmake.rs` Rust program, | |
| called the *recipe*. A recipe will be compiled and executed by compiletest with | |
| the `run_make_support` library linked in. | |
| If you need new utilities or functionality, consider extending and improving the | |
| [`run_make_support`] library. | |
| Compiletest directives like `//@ only-<target>` or `//@ ignore-<target>` are | |
| supported in `rmake.rs`, like in UI tests. | |
| However, revisions or building auxiliary via directives are not currently supported. | |
| `rmake.rs` and `run-make-support` may *not* use any nightly/unstable features, | |
| as they must be compilable by a stage 0 rustc that may be a beta or even stable rustc. | |
| By default, run-make tests print each subprocess command and its stdout/stderr. | |
| When running with `--no-capture` on `panic=abort` test suites (such as `cg_clif`), | |
| this can flood the terminal. | |
| Omit `--verbose-run-make-subprocess-output` to | |
| suppress this output for passing tests — failing tests always print regardless: | |
| ```bash | |
| ./x test tests/run-make --no-capture --verbose-run-make-subprocess-output=false | |
| ``` | |
| #### Quickly check if `rmake.rs` tests can be compiled | |
| You can quickly check if `rmake.rs` tests can be compiled without having to | |
| build stage1 rustc by forcing `rmake.rs` to be compiled with the stage0 compiler: | |
| ```bash | |
| $ COMPILETEST_FORCE_STAGE0=1 x test --stage 0 tests/run-make/<test-name> | |
| ``` | |
| Of course, some tests will not successfully *run* in this way. | |
| #### Using rust-analyzer with `rmake.rs` | |
| Like other test programs, the `rmake.rs` scripts used by run-make tests do not | |
| have rust-analyzer integration by default. | |
| To work around this when working on a particular test, temporarily create a | |
| `Cargo.toml` file in the test's directory | |
| (e.g. `tests/run-make/sysroot-crates-are-unstable/Cargo.toml`) | |
| with these contents: | |
| <div class="warning"> | |
| Be careful not to add this `Cargo.toml` or its `Cargo.lock` to your actual PR! | |
| </div> | |
| ```toml | |
| # Convince cargo that this isn't part of an enclosing workspace. | |
| [workspace] | |
| [package] | |
| name = "rmake" | |
| version = "0.1.0" | |
| edition = "2021" | |
| [dependencies] | |
| run_make_support = { path = "../../../src/tools/run-make-support" } | |
| [[bin]] | |
| name = "rmake" | |
| path = "rmake.rs" | |
| ``` | |
| Then add a corresponding entry to `"rust-analyzer.linkedProjects"` | |
| (e.g. in `.vscode/settings.json`): | |
| ```json | |
| "rust-analyzer.linkedProjects": [ | |
| "tests/run-make/sysroot-crates-are-unstable/Cargo.toml" | |
| ], | |
| ``` | |
| [`tests/run-make`]: https://github.com/rust-lang/rust/tree/HEAD/tests/run-make | |
| [`tests/run-make-cargo`]: https://github.com/rust-lang/rust/tree/HEAD/tests/run-make-cargo | |
| [`run_make_support`]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/run-make-support | |
| ### Coverage tests | |
| The tests in [`tests/coverage`] are shared by multiple test modes that test | |
| coverage instrumentation in different ways. | |
| Running the `coverage` test suite | |
| will automatically run each test in all of the different coverage modes. | |
| Each mode also has an alias to run the coverage tests in just that mode: | |
| ```bash | |
| ./x test coverage # runs all of tests/coverage in all coverage modes | |
| ./x test tests/coverage # same as above | |
| ./x test tests/coverage/if.rs # runs the specified test in all coverage modes | |
| ./x test coverage-map # runs all of tests/coverage in "coverage-map" mode only | |
| ./x test coverage-run # runs all of tests/coverage in "coverage-run" mode only | |
| ./x test coverage-map -- tests/coverage/if.rs # runs the specified test in "coverage-map" mode only | |
| ``` | |
| If a particular test should not be run in one of the coverage test modes for | |
| some reason, use the `//@ ignore-coverage-map` or `//@ ignore-coverage-run` directives. | |
| #### `coverage-map` suite | |
| In `coverage-map` mode, these tests verify the mappings between source code | |
| regions and coverage counters that are emitted by LLVM. | |
| They compile the test with `--emit llvm-ir`, then use a custom tool ([`src/tools/coverage-dump`]) to | |
| extract and pretty-print the coverage mappings embedded in the IR. | |
| These tests don't require the profiler runtime, so they run in PR CI jobs and are easy to | |
| run/bless locally. | |
| These coverage map tests can be sensitive to changes in MIR lowering or MIR | |
| optimizations, producing mappings that are different but produce identical coverage reports. | |
| As a rule of thumb, any PR that doesn't change coverage-specific code should | |
| **feel free to re-bless** the `coverage-map` tests as necessary, without | |
| worrying about the actual changes, as long as the `coverage-run` tests still pass. | |
| #### `coverage-run` suite | |
| In `coverage-run` mode, these tests perform an end-to-end test of coverage reporting. | |
| They compile a test program with coverage instrumentation, run that | |
| program to produce raw coverage data, and then use LLVM tools to process that | |
| data into a human-readable code coverage report. | |
| Instrumented binaries need to be linked against the LLVM profiler runtime, so | |
| `coverage-run` tests are **automatically skipped** unless the profiler runtime | |
| is enabled in `bootstrap.toml`: | |
| ```toml | |
| build.profiler = true | |
| ``` | |
| This also means that they typically don't run in PR CI jobs, though they do run | |
| as part of the full set of CI jobs used for merging. | |
| #### `coverage-run-rustdoc` suite | |
| The tests in [`tests/coverage-run-rustdoc`] also run instrumented doctests and | |
| include them in the coverage report. | |
| This avoids having to build rustdoc when only running the main `coverage` suite. | |
| [`tests/coverage`]: https://github.com/rust-lang/rust/tree/HEAD/tests/coverage | |
| [`src/tools/coverage-dump`]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/coverage-dump | |
| [`tests/coverage-run-rustdoc`]: https://github.com/rust-lang/rust/tree/HEAD/tests/coverage-run-rustdoc | |
| ### Crash tests | |
| [`tests/crashes`] serve as a collection of tests that are expected to cause the | |
| compiler to ICE, panic or crash in some other way, so that accidental fixes are tracked. | |
| Formerly, this was done at <https://github.com/rust-lang/glacier> but | |
| doing it inside the rust-lang/rust testsuite is more convenient. | |
| It is imperative that a test in the suite causes rustc to ICE, panic, or crash in some other way. | |
| A test will "pass" if rustc exits with an exit status other than 1 or 0. | |
| If you want to see verbose stdout/stderr, you need to set | |
| `COMPILETEST_VERBOSE_CRASHES=1`, e.g. | |
| ```bash | |
| $ COMPILETEST_VERBOSE_CRASHES=1 ./x test tests/crashes/999999.rs --stage 1 | |
| ``` | |
| Anyone can add ["untracked" crashes] from the issue tracker. | |
| It's strongly recommended to include test cases from several issues in a single PR. | |
| When you do so, each issue number should be noted in the file name (`12345.rs` | |
| should suffice) and also inside the file by means of a `//@ known-bug: #12345` directive. | |
| Please [label][labeling] the relevant issues with `S-bug-has-test` once your PR is merged. | |
| If you happen to fix one of the crashes, please move it to a fitting | |
| subdirectory in `tests/ui` and give it a meaningful name. | |
| Please add a doc comment at the top of the file explaining why this test exists. | |
| Even better will be if you can briefly explain how the example caused rustc to crash previously, | |
| and what was done to fix it. | |
| Adding | |
| ```text | |
| Fixes #NNNNN | |
| Fixes #MMMMM | |
| ``` | |
| to the description of your pull request will ensure the corresponding tickets be closed | |
| automatically upon merge. | |
| Make sure that your fix actually fixes the root cause of the issue and not just a subset first. | |
| The issue numbers can be found in the file name or the `//@ | |
| known-bug` directive inside the test file. | |
| [`tests/crashes`]: https://github.com/rust-lang/rust/tree/HEAD/tests/crashes | |
| ["untracked" crashes]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+state%3Aopen+label%3AI-ICE%2CI-crash+label%3AT-compiler+label%3AS-has-mcve+-label%3AS-bug-has-test | |
| [labeling]: https://forge.rust-lang.org/release/issue-triaging.html#applying-and-removing-labels | |
| ## Building auxiliary crates | |
| It is common that some tests require additional auxiliary crates to be compiled. | |
| There are multiple [directives](directives.md) to assist with that: | |
| - `aux-build` | |
| - `aux-crate` | |
| - `aux-bin` | |
| - `aux-codegen-backend` | |
| - `proc-macro` | |
| `aux-build` will build a separate crate from the named source file. | |
| The source file should be in a directory called `auxiliary` beside the test file. | |
| ```rust,ignore | |
| //@ aux-build: my-helper.rs | |
| extern crate my_helper; | |
| // ... You can use my_helper. | |
| ``` | |
| The aux crate will be built as a dylib if possible (unless on a platform that | |
| does not support them, or the `no-prefer-dynamic` header is specified in the aux file). | |
| The `-L` flag is used to find the extern crates. | |
| `aux-crate` is very similar to `aux-build`. | |
| However, it uses the `--extern` flag | |
| to link to the extern crate to make the crate be available as an extern prelude. | |
| That allows you to specify the additional syntax of the `--extern` flag, such as | |
| renaming a dependency. | |
| For example, `//@ aux-crate: foo=bar.rs` will compile | |
| `auxiliary/bar.rs` and make it available under the name `foo` within the test. | |
| This is similar to how Cargo does dependency renaming. | |
| It is also possible to specify [`--extern` modifiers]. | |
| For example, `//@ aux-crate: noprelude:foo=bar.rs`. | |
| `aux-bin` is similar to `aux-build` but will build a binary instead of a library. | |
| The binary will be available in `auxiliary/bin` relative to the working directory of the test. | |
| `aux-codegen-backend` is similar to `aux-build`, but will then pass the compiled | |
| dylib to `-Zcodegen-backend` when building the main file. | |
| This will only work for tests in `tests/ui-fulldeps`, since it requires the use of compiler crates. | |
| ### Auxiliary proc-macro | |
| If you want a proc-macro dependency, then you can use the `proc-macro` | |
| directive. This directive behaves just like `aux-build`, i.e. that you should | |
| place the proc-macro test auxiliary file under a `auxiliary` folder under the | |
| same parent folder as the main test file. | |
| However, it also has four additional | |
| preset behavior compared to `aux-build` for the proc-macro test auxiliary: | |
| 1. The aux test file is built with `--crate-type proc-macro`. | |
| 2. The aux test file is built without `-C prefer-dynamic`, i.e. it will not try | |
| to produce a dylib for the aux crate. | |
| 3. The aux crate is made available to the test file via extern prelude with | |
| `--extern <aux_crate_name>`. | |
| Note that since UI tests default to edition | |
| 2015, you still need to specify `extern <aux_crate_name>` unless the main | |
| test file is using an edition that is 2018 or newer if you want to use the | |
| aux crate name in a `use` import. | |
| 4. The `proc_macro` crate is made available as an extern prelude module. | |
| The same edition 2015 vs newer edition distinction for `extern proc_macro;` applies. | |
| For example, you might have a test `tests/ui/cat/meow.rs` and proc-macro | |
| auxiliary `tests/ui/cat/auxiliary/whiskers.rs`: | |
| ```text | |
| tests/ui/cat/ | |
| meow.rs # main test file | |
| auxiliary/whiskers.rs # auxiliary | |
| ``` | |
| ```rs | |
| // tests/ui/cat/meow.rs | |
| //@ proc-macro: whiskers.rs | |
| extern crate whiskers; // needed as ui test defaults to edition 2015 | |
| fn main() { | |
| whiskers::identity!(); | |
| } | |
| ``` | |
| ```rs | |
| // tests/ui/cat/auxiliary/whiskers.rs | |
| extern crate proc_macro; | |
| use proc_macro::*; | |
| #[proc_macro] | |
| pub fn identity(ts: TokenStream) -> TokenStream { | |
| ts | |
| } | |
| ``` | |
| > **Note**: The `proc-macro` header currently does not work with the | |
| > `build-aux-doc` header for rustdoc tests. In that case, you will need to use | |
| > the `aux-build` header, and use `#![crate_type="proc_macro"]`, and `//@ | |
| > force-host` and `//@ no-prefer-dynamic` headers in the proc-macro. | |
| ## Revisions | |
| Revisions allow a single test file to be used for multiple tests. | |
| This is done by adding a special directive at the top of the file: | |
| ```rust,ignore | |
| //@ revisions: foo bar baz | |
| ``` | |
| This will result in the test being compiled (and tested) three times, once with | |
| `--cfg foo`, once with `--cfg bar`, and once with `--cfg baz`. | |
| You can therefore use `#[cfg(foo)]` etc within the test to tweak each of these results. | |
| You can also customize directives and expected error messages to a particular revision. | |
| To do this, add `[revision-name]` after the `//@` for directives, and | |
| after `//` for UI error annotations, like so: | |
| ```rust,ignore | |
| // A flag to pass in only for cfg `foo`: | |
| //@[foo]compile-flags: -Z verbose-internals | |
| #[cfg(foo)] | |
| fn test_foo() { | |
| let x: usize = 32_u32; //[foo]~ ERROR mismatched types | |
| } | |
| ``` | |
| Multiple revisions can be specified in a comma-separated list, such as `//[foo,bar,baz]~^`. | |
| In test suites that use the LLVM [FileCheck] tool, the current revision name is | |
| also registered as an additional prefix for FileCheck directives: | |
| ```rust,ignore | |
| //@ revisions: NORMAL COVERAGE | |
| //@[COVERAGE] compile-flags: -Cinstrument-coverage | |
| //@[COVERAGE] needs-profiler-runtime | |
| // COVERAGE: @__llvm_coverage_mapping | |
| // NORMAL-NOT: @__llvm_coverage_mapping | |
| // CHECK: main | |
| fn main() {} | |
| ``` | |
| Note that not all directives have meaning when customized to a revision. | |
| For example, the `ignore-test` directives (and all "ignore" directives) currently | |
| only apply to the test as a whole, not to particular revisions. | |
| The only directives that are intended to really work when customized to a revision are | |
| error patterns and compiler flags. | |
| <!-- date-check Feb 2026 --> | |
| > Note that these test suites do not support revisions: | |
| > - `codegen-units` | |
| > - `run-make` | |
| > - `rustdoc-html` | |
| > - `rustdoc-json` | |
| ### Ignoring unused revision names | |
| Normally, revision names mentioned in other directives and error annotations | |
| must correspond to an actual revision declared in a `revisions` directive. | |
| This is enforced by an `./x test tidy` check. | |
| If a revision name needs to be temporarily removed from the revision list for | |
| some reason, the above check can be suppressed by adding the revision name to an | |
| `//@ unused-revision-names:` header instead. | |
| Specifying an unused name of `*` (i.e. `//@ unused-revision-names: *`) will | |
| permit any unused revision name to be mentioned. | |
| ## Compare modes | |
| Compiletest can be run in different modes, called _compare modes_, which can be | |
| used to compare the behavior of all tests with different compiler flags enabled. | |
| This can help highlight what differences might appear with certain flags, and | |
| check for any problems that might arise. | |
| To run the tests in a different mode, you need to pass the `--compare-mode` CLI flag: | |
| ```bash | |
| ./x test tests/ui --compare-mode=next-solver | |
| ``` | |
| The possible compare modes are: | |
| - `polonius` — Runs with Polonius with `-Zpolonius=next`. | |
| - `next-solver` — Runs with the next trait solver with `-Znext-solver`. | |
| - `next-solver-coherence` — Runs coherence with the next trait solver with `-Znext-solver=coherence`. | |
| - `split-dwarf` — Runs with unpacked split-DWARF with `-Csplit-debuginfo=unpacked`. | |
| - `split-dwarf-single` — Runs with packed split-DWARF with `-Csplit-debuginfo=packed`. | |
| See [UI compare modes](ui.md#compare-modes) for more information about how UI | |
| tests support different output for different modes. | |
| In CI, compare modes are only used in one Linux builder, and only with the following settings: | |
| - `tests/debuginfo`: Uses `split-dwarf` mode. | |
| This helps ensure that none of the debuginfo tests are affected when enabling split-DWARF. | |
| Note that compare modes are separate to [revisions](#revisions). | |
| All revisions are tested when running `./x test tests/ui`, however compare-modes must be | |
| manually run individually via the `--compare-mode` flag. | |
| ## Parallel frontend | |
| Compiletest can be run with the `--parallel-frontend-threads` flag to run the compiler in parallel mode. | |
| This can be used to check that the compiler produces the same output in parallel mode as in non-parallel mode, and to check for any issues that might arise in parallel mode. | |
| To run the tests in parallel mode, you need to pass the `--parallel-frontend-threads` CLI flag: | |
| ```bash | |
| ./x test tests/ui -- --parallel-frontend-threads=N --iteration-count=M | |
| ``` | |
| Where `N` is the number of threads to use for the parallel frontend, and `M` is the number of times to run each test in parallel mode (to increase the chances of catching any non-determinism). | |
| Also, when running with `--parallel-frontend-threads`, the `compare-output-by-lines` directive would be implied for all tests, since the output from the parallel frontend can be non-deterministic in terms of the order of lines. | |
| The parallel frontend is available in UI tests only at the moment, and is not currently supported in other test suites. | |
| [`--extern` modifiers]: https://github.com/rust-lang/rust/issues/98405 |