line/column information would be retained, but small changes to the source
causes large diffs, and more frequent merge conflicts and test errors.
Sometimes these built-in normalizations are not enough. In such cases, you may
provide custom normalization rules using `normalize-*` directives, e.g.
```rust,ignore
//@ normalize-stdout: "foo" -> "bar"
//@ normalize-stderr: "foo" -> "bar"
//@ normalize-stderr-32bit: "fn\(\) \(32 bits\)" -> "fn\(\) \($$PTR bits\)"
//@ normalize-stderr-64bit: "fn\(\) \(64 bits\)" -> "fn\(\) \($$PTR bits\)"
```
This tells the test, on 32-bit platforms, whenever the compiler writes `fn() (32
bits)` to stderr, it should be normalized to read `fn() ($PTR bits)` instead.
Similar for 64-bit. The replacement is performed by regexes using default regex
flavor provided by `regex` crate.
The corresponding reference file will use the normalized output to test both
32-bit and 64-bit platforms:
```text
...
|
= note: source type: fn() ($PTR bits)
= note: target type: u16 (16 bits)
...
```
Please see [`ui/transmute/main.rs`][mrs] and [`main.stderr`] for a concrete
usage example.
## Error annotations
Error annotations specify the errors that the compiler is expected to emit. They
are "attached" to the line in source where the error is located.
```rust,ignore
fn main() {
boom //~ ERROR cannot find value `boom` in this scope [E0425]
}
```
Although UI tests have a `.stderr` file which contains the entire compiler
output, UI tests require that errors are also annotated within the source. This
redundancy helps avoid mistakes since the `.stderr` files are usually
auto-generated. It also helps to directly see where the error spans are expected
to point to by looking at one file instead of having to compare the `.stderr`
file with the source. Finally, they ensure that no additional unexpected errors
are generated.
They have several forms, but generally are a comment with the diagnostic level
(such as `ERROR`) and a substring of the expected error output. You don't have
to write out the entire message, just make sure to include the important part of
the message to make it self-documenting.
Most error annotations need to match with the line of the diagnostic. There are
several ways to match the message with the line (see the examples below):
* `~`: Associates the error level and message with the *current* line
* `~^`: Associates the error level and message with the *previous* error
annotation line. Each caret (`^`) that you add adds a line to this, so `~^^^`
is three lines above the error annotation line.
* `~|`: Associates the error level and message with the *same* line as the
*previous comment*. This is more convenient than using multiple carets when
there are multiple messages associated with the same line.
* `~v`: Associates the error level and message with the *next* error
annotation line. Each symbol (`v`) that you add adds a line to this, so `~vvv`
is three lines below the error annotation line.
Example:
```rust,ignore
let _ = same_line; //~ ERROR undeclared variable
fn meow(_: [u8]) {}
//~^ ERROR unsized
//~| ERROR anonymous parameters
```
The space character between `//~` (or other variants) and the subsequent text is
negligible (i.e. there is no semantic difference between `//~ ERROR` and
`//~ERROR` although the former is more common in the codebase).
`~? <diagnostic kind>` (example being `~? ERROR`)
is used to match diagnostics _without_ line info at all,
or where the line info is outside the main test file[^main test file].
These annotations can be placed on any line in the test file.
as distinct from aux files, or sources that we have no control over.
### Error annotation examples
Here are examples of error annotations on different lines of UI test source.
#### Positioned on error line
Use the `//~ ERROR` idiom:
```rust,ignore
fn main() {
let x = (1, 2, 3);
match x {
(_a, _x @ ..) => {} //~ ERROR `_x @` is not allowed in a tuple
_ => {}
}