Skip to content

Commit 5106793

Browse files
committed
Add info about emitting lints and errors
1 parent bb86786 commit 5106793

File tree

3 files changed

+180
-0
lines changed

3 files changed

+180
-0
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- [miri const evaluator](./miri.md)
5555
- [Parameter Environments](./param_env.md)
5656
- [Generating LLVM IR](./trans.md)
57+
- [Emitting Diagnostics](./diag.md)
5758

5859
---
5960

src/appendix-code-index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ Item | Kind | Short description | Chapter |
88
----------------|----------|-----------------------------|--------------------|-------------------
99
`CodeMap` | struct | The CodeMap maps the AST nodes to their source code | [The parser] | [src/libsyntax/codemap.rs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/codemap/struct.CodeMap.html)
1010
`CompileState` | struct | State that is passed to a callback at each compiler pass | [The Rustc Driver] | [src/librustc_driver/driver.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/driver/struct.CompileState.html)
11+
`DiagnosticBuilder` | struct | A struct for building up compiler diagnostics, such as errors or lints | [Emitting Diagnostics] | [src/librustc_errors/diagnostic_builder.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagnosticBuilder.html)
1112
`DocContext` | struct | A state container used by rustdoc when crawling through a crate to gather its documentation | [Rustdoc] | [src/librustdoc/core.rs](https://github.com/rust-lang/rust/blob/master/src/librustdoc/core.rs)
1213
`ast::Crate` | struct | Syntax-level representation of a parsed crate | [The parser] | [src/librustc/hir/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/struct.Crate.html)
1314
`hir::Crate` | struct | More abstract, compiler-friendly form of a crate's AST | [The Hir] | [src/librustc/hir/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/hir/struct.Crate.html)
1415
`ParseSess` | struct | This struct contains information about a parsing session | [the Parser] | [src/libsyntax/parse/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/parse/struct.ParseSess.html)
1516
`Session` | struct | The data associated with a compilation session | [the Parser], [The Rustc Driver] | [src/librustc/session/mod.html](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/session/struct.Session.html)
17+
`Span` | struct | A location in the user's source code, used for error reporting primarily | [Emitting Diagnostics] | [src/libsyntax_pos/span_encoding.rs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax_pos/struct.Span.html)
1618
`StringReader` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] | [src/libsyntax/parse/lexer/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/parse/lexer/struct.StringReader.html)
1719
`TraitDef` | struct | This struct contains a trait's definition with type information | [The `ty` modules] | [src/librustc/ty/trait_def.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/trait_def/struct.TraitDef.html)
1820
`Ty<'tcx>` | struct | This is the internal representation of a type used for type checking | [Type checking] | [src/librustc/ty/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/type.Ty.html)
@@ -24,3 +26,4 @@ Item | Kind | Short description | Chapter |
2426
[Type checking]: type-checking.html
2527
[The `ty` modules]: ty.html
2628
[Rustdoc]: rustdoc.html
29+
[Emitting Diagnostics]: diag.html

src/diag.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Emitting Diagnostics
2+
3+
A lot of effort has been put into making `rustc` have great error messages.
4+
This chapter is about how to emit compile errors and lints from the compiler.
5+
6+
## `Span`
7+
8+
`Span` is the primary data structure in `rustc` used to represent a location in
9+
the code being compiled. `Span`s are attached to most constructs in HIR and MIR,
10+
allowing for easier error reporting whenever an error comes up.
11+
12+
A `Span` can be looked up in a `CodeMap` to get a "snippet" useful for
13+
displaying errors with [`span_to_snippet` and other similar methods][sptosnip]
14+
on the `CodeMap`.
15+
16+
[sptosnip]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/codemap/struct.CodeMap.html#method.span_to_snippet
17+
18+
## Error messages
19+
20+
The [`rustc_errors`][errors] crate defines most of the utilities used for
21+
reporting errors.
22+
23+
[errors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html
24+
25+
Most "session"-like types in the compiler (e.g. [`Session`][session]) have
26+
methods (or fields with methods) that allow reporting errors. These methods
27+
usually have names like `span_err` or `struct_span_err` or `span_warn`, etc...
28+
There are lots of them; they emit different types of "errors", such as
29+
warnings, errors, fatal errors, suggestions, etc.
30+
31+
[session]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/session/struct.Session.html
32+
33+
In general, there are two class of such methods: ones that emit an error
34+
directly and ones that allow finer control over what to emit. For example,
35+
[`span_err`][spanerr] emits the given error message at the given `Span`, but
36+
[`struct_span_err`][strspanerr] instead returns a [`DiagnosticBuilder`][diagbuild].
37+
38+
`DiagnosticBuilder` allows you to add related notes and suggestions to an error
39+
before emitting it by calling the [`emit`][emit] method. See the
40+
[docs][diagbuild] for more info on what you can do.
41+
42+
[spanerr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/session/struct.Session.html#method.span_err
43+
[strspanerr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/session/struct.Session.html#method.struct_span_err
44+
[diagbuild]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html
45+
[emit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html#method.emit
46+
47+
For example, to add a help message to an error, one might do:
48+
49+
```rust,ignore
50+
let snip = sess.codemap().span_to_snippet(sp);
51+
52+
sess.struct_span_err(sp, "oh no! this is an error!")
53+
.span_suggestion(other_sp, "try using a qux here", format!("qux {}", snip))
54+
.emit();
55+
```
56+
57+
This might emit an error like
58+
59+
```console
60+
$ rustc mycode.rs
61+
error[E0999]: oh no! this is an error!
62+
--> mycode.rs:3:5
63+
|
64+
3 | sad()
65+
| ^ help: try using a qux here: `qux sad()`
66+
67+
error: aborting due to previous error
68+
69+
For more information about this error, try `rustc --explain E0999`.
70+
```
71+
72+
## Lints
73+
74+
The compiler linting infrastructure is defined in the [`rustc::lint`][rlint]
75+
module.
76+
77+
[rlint]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/index.html
78+
79+
### Declaring a lint
80+
81+
The built-in compiler lints are defined in the [`rustc_lint`][builtin]
82+
crate.
83+
84+
[builtin]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/index.html
85+
86+
Each lint is defined as a `struct` that implements the `LintPass` `trait`. The
87+
trait implementation allows you to check certain syntactic constructs the
88+
linter walks the source code. You can then choose to emit lints in a very
89+
similar way to compile errors. Finally, you register the lint to actually get
90+
it to be run by the compiler by using the `declare_lint!` macro.
91+
92+
For example, the following lint checks for uses
93+
of `while true { ... }` and suggests using `loop { ... }` instead.
94+
95+
```rust,ignore
96+
// Declare a lint called `WHILE_TRUE`
97+
declare_lint! {
98+
WHILE_TRUE,
99+
100+
// warn-by-default
101+
Warn,
102+
103+
// This string is the lint description
104+
"suggest using `loop { }` instead of `while true { }`"
105+
}
106+
107+
// Define a struct and `impl LintPass` for it.
108+
#[derive(Copy, Clone)]
109+
pub struct WhileTrue;
110+
111+
impl LintPass for WhileTrue {
112+
fn get_lints(&self) -> LintArray {
113+
lint_array!(WHILE_TRUE)
114+
}
115+
}
116+
117+
// LateLintPass has lots of methods. We only override the definition of
118+
// `check_expr` for this lint because that's all we need, but you could
119+
// override other methods for your own lint. See the rustc docs for a full
120+
// list of methods.
121+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue {
122+
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
123+
if let hir::ExprWhile(ref cond, ..) = e.node {
124+
if let hir::ExprLit(ref lit) = cond.node {
125+
if let ast::LitKind::Bool(true) = lit.node {
126+
if lit.span.ctxt() == SyntaxContext::empty() {
127+
let msg = "denote infinite loops with `loop { ... }`";
128+
let condition_span = cx.tcx.sess.codemap().def_span(e.span);
129+
let mut err = cx.struct_span_lint(WHILE_TRUE, condition_span, msg);
130+
err.span_suggestion_short(condition_span, "use `loop`", "loop".to_owned());
131+
err.emit();
132+
}
133+
}
134+
}
135+
}
136+
}
137+
}
138+
```
139+
140+
### Edition Lints
141+
142+
Sometimes we want to change the behavior of a lint in a new edition. To do this,
143+
we just add the transition to our invocation of `declare_lint!`:
144+
145+
```rust,ignore
146+
declare_lint! {
147+
pub ANONYMOUS_PARAMETERS,
148+
Allow,
149+
"detects anonymous parameters",
150+
Edition::Edition2018 => Warn,
151+
}
152+
```
153+
154+
This makes the `ANONYMOUS_PARAMETERS` lint allow-by-default in the 2015 edition
155+
but warn-by-default in the 2018 edition.
156+
157+
### Lint Groups
158+
159+
Lints can be turned on in groups. These groups are declared in the
160+
[`register_builtins`][rbuiltins] function in [`rustc_lint::lib`][builtin]. The
161+
`add_lint_group!` macro is used to declare a new group.
162+
163+
[rbuiltins]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html
164+
165+
For example,
166+
167+
```rust,ignore
168+
add_lint_group!(sess,
169+
"nonstandard_style",
170+
NON_CAMEL_CASE_TYPES,
171+
NON_SNAKE_CASE,
172+
NON_UPPER_CASE_GLOBALS);
173+
```
174+
175+
This defines the `nonstandard_style` group which turns on the listed lints. A user
176+
can turn on these lints by using `!#[warn(nonstandard_style)]`.

0 commit comments

Comments
 (0)