- When emitting a message with span, try to reduce the span to the smallest
amount possible that still signifies the issue
- Try not to emit multiple error messages for the same error. This may require
detecting duplicates.
- When the compiler has too little information for a specific error message,
consult with the compiler team to add new attributes for library code that
allow adding more information. For example see
[`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these
annotations when available!
- Keep in mind that Rust's learning curve is rather steep, and that the
compiler messages are an important learning tool.
- When talking about the compiler, call it `the compiler`, not `Rust` or
`rustc`.
- Use the [Oxford comma](https://en.wikipedia.org/wiki/Serial_comma) when
writing lists of items.
### Lint naming
From [RFC 0344], lint names should be consistent, with the following
guidelines:
The basic rule is: the lint name should make sense when read as "allow
*lint-name*" or "allow *lint-name* items". For example, "allow
`deprecated` items" and "allow `dead_code`" makes sense, while "allow
`unsafe_block`" is ungrammatical (should be plural).
- Lint names should state the bad thing being checked for, e.g. `deprecated`,
so that `#[allow(deprecated)]` (items) reads correctly. Thus `ctypes` is not
an appropriate name; `improper_ctypes` is.
- Lints that apply to arbitrary items (like the stability lints) should just
mention what they check for: use `deprecated` rather than
`deprecated_items`. This keeps lint names short. (Again, think "allow
*lint-name* items".)
- If a lint applies to a specific grammatical class, mention that class and
use the plural form: use `unused_variables` rather than `unused_variable`.
This makes `#[allow(unused_variables)]` read correctly.
- Lints that catch unnecessary, unused, or useless aspects of code should use
the term `unused`, e.g. `unused_imports`, `unused_typecasts`.
- Use snake case in the same way you would for function names.
### Diagnostic levels
Guidelines for different diagnostic levels:
- `error`: emitted when the compiler detects a problem that makes it unable to
compile the program, either because the program is invalid or the programmer
has decided to make a specific `warning` into an error.
- `warning`: emitted when the compiler detects something odd about a program.
Care should be taken when adding warnings to avoid warning fatigue, and
avoid false-positives where there really isn't a problem with the code. Some
examples of when it is appropriate to issue a warning:
- A situation where the user *should* take action, such as swap out a
deprecated item, or use a `Result`, but otherwise doesn't prevent
compilation.
- Unnecessary syntax that can be removed without affecting the semantics of
the code. For example, unused code, or unnecessary `unsafe`.
- Code that is very likely to be incorrect, dangerous, or confusing, but the
language technically allows, and is not ready or confident enough to make
an error. For example `unused_comparisons` (out of bounds comparisons) or
`bindings_with_variant_name` (the user likely did not intend to create a
binding in a pattern).
- [Future-incompatible lints](#future-incompatible), where something was
accidentally or erroneously accepted in the past, but rejecting would
cause excessive breakage in the ecosystem.
- Stylistic choices. For example, camel or snake case, or the `dyn` trait
warning in the 2018 edition. These have a high bar to be added, and should
only be used in exceptional circumstances. Other stylistic choices should
either be allow-by-default lints, or part of other tools like Clippy or
rustfmt.
- `help`: emitted following an `error` or `warning` to give additional
information to the user about how to solve their problem. These messages
often include a suggestion string and [`rustc_errors::Applicability`]