|
3 | 3 | A lot of effort has been put into making `rustc` have great error messages.
|
4 | 4 | This chapter is about how to emit compile errors and lints from the compiler.
|
5 | 5 |
|
6 |
| -## Diagnostic output style guide |
| 6 | +## Diagnostic structure |
7 | 7 |
|
8 | 8 | The main parts of a diagnostic error are the following:
|
9 | 9 |
|
@@ -61,6 +61,163 @@ error: the fobrulator needs to be krontrificated
|
61 | 61 | When code or an identifier must appear in an message or label, it should be
|
62 | 62 | surrounded with single acute accents \`.
|
63 | 63 |
|
| 64 | +### Error explanations |
| 65 | + |
| 66 | +Some errors include long form descriptions. They may be viewed with the |
| 67 | +`--explain` flag, or via the [error index]. Each explanation comes with an |
| 68 | +example of how to trigger it and advice on how to fix it. |
| 69 | + |
| 70 | +Please read [RFC 1567] for details on how to format and write long error |
| 71 | +codes. |
| 72 | + |
| 73 | +The descriptions are written in markdown, and all of them are linked in the |
| 74 | +[`librustc_error_codes`] crate. |
| 75 | + |
| 76 | +<!-- TODO: When should an error use an error code, and when shouldn't it? --> |
| 77 | + |
| 78 | +[`librustc_error_codes`]: https://github.com/rust-lang/rust/blob/master/src/librustc_error_codes/error_codes.rs |
| 79 | +[error index]: https://doc.rust-lang.org/error-index.html |
| 80 | +[RFC 1567]: https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md |
| 81 | + |
| 82 | +### Lints versus fixed diagnostics |
| 83 | + |
| 84 | +Some messages are emitted via [lints](#lints), where the user can control the |
| 85 | +level. Some are hard-coded such that the user cannot control the level. |
| 86 | + |
| 87 | +Hard-coded warnings should be avoided for normal code, preferring to use lints |
| 88 | +instead. Some cases, such as warnings with CLI flags will require the use of |
| 89 | +hard-coded warnings. |
| 90 | + |
| 91 | +See the `deny` [lint level](#diagnostic-levels) below for guidelines when to |
| 92 | +use an error-level lint instead of a fixed error. |
| 93 | + |
| 94 | +## Diagnostic output style guide |
| 95 | + |
| 96 | +- Write in plain simple English. If your message, when shown on a – possibly |
| 97 | + small – screen (which hasn't been cleaned for a while), cannot be understood |
| 98 | + by a normal programmer, who just came out of bed after a night partying, |
| 99 | + it's too complex. |
| 100 | +- `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase |
| 101 | + letter and do not end with punctuation. |
| 102 | +- Error messages should be succinct. Users will see these error messages many |
| 103 | + times, and more verbose descriptions can be viewed with the `--explain` |
| 104 | + flag. That said, don't make it so terse that it's hard to understand. |
| 105 | +- The word "illegal" is illegal. Prefer "invalid" or a more specific word |
| 106 | + instead. |
| 107 | +- Errors should document the span of code where they occur – the `span_..` |
| 108 | + methods allow to easily do this. Also `note` other spans that have |
| 109 | + contributed to the error if the span isn't too large. |
| 110 | +- When emitting a message with span, try to reduce the span to the smallest |
| 111 | + amount possible that still signifies the issue |
| 112 | +- Try not to emit multiple error messages for the same error. This may require |
| 113 | + detecting duplicates. |
| 114 | +- When the compiler has too little information for a specific error message, |
| 115 | + lobby for annotations for library code that allow adding more. For example |
| 116 | + see [`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these |
| 117 | + annotations when available! |
| 118 | +- Keep in mind that Rust's learning curve is rather steep, and that the |
| 119 | + compiler messages are an important learning tool. |
| 120 | +- When talking about the compiler, call it `the compiler`, not `Rust` or |
| 121 | + `rustc`. |
| 122 | + |
| 123 | +### Lint naming |
| 124 | + |
| 125 | +From [RFC 0344], lint names should be consistent, with the following |
| 126 | +guidelines: |
| 127 | + |
| 128 | +The basic rule is: the lint name should make sense when read as "allow |
| 129 | +*lint-name*" or "allow *lint-name* items". For example, "allow |
| 130 | +`deprecated` items" and "allow `dead_code`" makes sense, while "allow |
| 131 | +`unsafe_block`" is ungrammatical (should be plural). |
| 132 | + |
| 133 | +- Lint names should state the bad thing being checked for, e.g. `deprecated`, |
| 134 | + so that `#[allow(deprecated)]` (items) reads correctly. Thus `ctypes` is not |
| 135 | + an appropriate name; `improper_ctypes` is. |
| 136 | + |
| 137 | +- Lints that apply to arbitrary items (like the stability lints) should just |
| 138 | + mention what they check for: use `deprecated` rather than |
| 139 | + `deprecated_items`. This keeps lint names short. (Again, think "allow |
| 140 | + *lint-name* items".) |
| 141 | + |
| 142 | +- If a lint applies to a specific grammatical class, mention that class and |
| 143 | + use the plural form: use `unused_variables` rather than `unused_variable`. |
| 144 | + This makes `#[allow(unused_variables)]` read correctly. |
| 145 | + |
| 146 | +- Lints that catch unnecessary, unused, or useless aspects of code should use |
| 147 | + the term `unused`, e.g. `unused_imports`, `unused_typecasts`. |
| 148 | + |
| 149 | +- Use snake case in the same way you would for function names. |
| 150 | + |
| 151 | +[RFC 0344]: https://github.com/rust-lang/rfcs/blob/master/text/0344-conventions-galore.md#lints |
| 152 | + |
| 153 | +### Diagnostic levels |
| 154 | + |
| 155 | +Guidelines for different diagnostic levels: |
| 156 | + |
| 157 | +- `error`: emitted when the compiler detects a problem that makes it unable to |
| 158 | + compile the program, either because the program is invalid or the programmer |
| 159 | + has decided to make a specific `warning` into an error. |
| 160 | + |
| 161 | +- `warning`: emitted when the compiler detects something odd about a program. |
| 162 | + Care should be taken when adding warnings to avoid warning fatigue, and |
| 163 | + avoid false-positives where there really isn't a problem with the code. Some |
| 164 | + examples of when it is appropriate to issue a warning: |
| 165 | + |
| 166 | + - A situation where the user *should* take action, such as swap out a |
| 167 | + deprecated item, or use a `Result`, but otherwise doesn't prevent |
| 168 | + compilation. |
| 169 | + - Unnecessary syntax that can be removed without affecting the semantics of |
| 170 | + the code. For example, unused code, or unnecessary `unsafe`. |
| 171 | + - Code that is very likely to be incorrect, dangerous, or confusing, but the |
| 172 | + language technically allows, and is not ready or confident enough to make |
| 173 | + an error. For example `unused_comparisons` (out of bounds comparisons) or |
| 174 | + `bindings_with_variant_name` (the user likely did not intend to create a |
| 175 | + binding in a pattern). |
| 176 | + - [Future-incompatible lints](#future-incompatible), where something was |
| 177 | + accidentally or erroneously accepted in the past, but rejecting would |
| 178 | + cause excessive breakage in the ecosystem. |
| 179 | + - Stylistic choices. For example, camel or snake case, or the `dyn` trait |
| 180 | + warning in the 2018 edition. These have a high bar to be added, and should |
| 181 | + only be used in exceptional circumstances. Other stylistic choices should |
| 182 | + either be allow-by-default lints, or part of other tools like Clippy or |
| 183 | + rustfmt. |
| 184 | + |
| 185 | +- `help`: emitted following an `error` or `warning` to give additional |
| 186 | + information to the user about how to solve their problem. The error or |
| 187 | + warning portion should *not* suggest how to fix the problem, only the "help" |
| 188 | + sub-diagnostic should. |
| 189 | + |
| 190 | +- `note`: emitted to identify additional circumstances and parts of the code |
| 191 | + that caused the warning or error. For example, the borrow checker will note |
| 192 | + any previous conflicting borrows. |
| 193 | + |
| 194 | +Not to be confused with *lint levels*, whose guidelines are: |
| 195 | + |
| 196 | +- `forbid`: Lints should never default to `forbid`. |
| 197 | +- `deny`: Equivalent to `error` diagnostic level. Some examples: |
| 198 | + |
| 199 | + - A future-incompatible or edition-based lint that has graduated from the |
| 200 | + warning level. |
| 201 | + - Something that has an extremely high confidence that is incorrect, but |
| 202 | + still want an escape hatch to allow it to pass. |
| 203 | + |
| 204 | +- `warn`: Equivalent to the `warning` diagnostic level. See `warning` above |
| 205 | + for guidelines. |
| 206 | +- `allow`: Examples of the kinds of lints that should default to `allow`: |
| 207 | + |
| 208 | + - The lint has a too high false positive rate. |
| 209 | + - The lint is too opinionated. |
| 210 | + - The lint is experimental. |
| 211 | + - The lint is used for enforcing something that is not normally enforced. |
| 212 | + For example, the `unsafe_code` lint can be used to prevent usage of unsafe |
| 213 | + code. |
| 214 | + |
| 215 | +More information about lint levels can be found in the [rustc |
| 216 | +book][rustc-lint-levels] and the [reference][reference-diagnostics]. |
| 217 | + |
| 218 | +[reference-diagnostics]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#lint-check-attributes |
| 219 | +[rustc-lint-levels]: https://doc.rust-lang.org/nightly/rustc/lints/levels.html |
| 220 | + |
64 | 221 | ## Helpful tips and options
|
65 | 222 |
|
66 | 223 | ### Finding the source of errors
|
@@ -373,6 +530,7 @@ If you need a combination of options that's not supported by the
|
373 | 530 | `declare_lint!` macro, you can always define your own static with a type of
|
374 | 531 | `&Lint` but this is currently linted against in the compiler tree.
|
375 | 532 |
|
| 533 | +<a id="future-incompatible"></a> |
376 | 534 | #### Guidelines for creating a future incompatibility lint
|
377 | 535 |
|
378 | 536 | - Create a lint defaulting to warn as normal, with ideally the same error
|
|
0 commit comments