]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md
New upstream version 1.65.0+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / diagnostics / diagnostic-structs.md
CommitLineData
923072b8
FG
1# Diagnostic and subdiagnostic structs
2rustc has two diagnostic derives that can be used to create simple diagnostics,
3which are recommended to be used when they are applicable:
4`#[derive(SessionDiagnostic)]` and `#[derive(SessionSubdiagnostic)]`.
5
6Diagnostics created with the derive macros can be translated into different
7languages and each has a slug that uniquely identifies the diagnostic.
8
9## `#[derive(SessionDiagnostic)]`
10Instead of using the `DiagnosticBuilder` API to create and emit diagnostics,
11the `SessionDiagnostic` derive can be used. `#[derive(SessionDiagnostic)]` is
12only applicable for simple diagnostics that don't require much logic in
13deciding whether or not to add additional subdiagnostics.
14
15Consider the [definition][defn] of the "field already declared" diagnostic
16shown below:
17
18```rust,ignore
19#[derive(SessionDiagnostic)]
f2b60f7d 20#[diag(typeck::field_already_declared, code = "E0124")]
923072b8
FG
21pub struct FieldAlreadyDeclared {
22 pub field_name: Ident,
23 #[primary_span]
24 #[label]
25 pub span: Span,
f2b60f7d 26 #[label(typeck::previous_decl_label)]
923072b8
FG
27 pub prev_span: Span,
28}
29```
30
31`SessionDiagnostic` can only be applied to structs. Every `SessionDiagnostic`
f2b60f7d 32has to have one attribute, `#[diag(...)]`, applied to the struct itself.
923072b8
FG
33
34If an error has an error code (e.g. "E0624"), then that can be specified using
35the `code` sub-attribute. Specifying a `code` isn't mandatory, but if you are
36porting a diagnostic that uses `DiagnosticBuilder` to use `SessionDiagnostic`
37then you should keep the code if there was one.
38
f2b60f7d
FG
39`#[diag(..)]` must provide a slug as the first positional argument (a path to an
40item in `rustc_errors::fluent::*`). A slug uniquely identifies the diagnostic
41and is also how the compiler knows what error message to emit (in the default
42locale of the compiler, or in the locale requested by the user). See
43[translation documentation](./translation.md) to learn more about how
44translatable error messages are written and how slug items are generated.
923072b8
FG
45
46In our example, the Fluent message for the "field already declared" diagnostic
47looks like this:
48
49```fluent
f2b60f7d 50typeck_field_already_declared =
923072b8
FG
51 field `{$field_name}` is already declared
52 .label = field already declared
f2b60f7d 53 .previous_decl_label = `{$field_name}` first declared here
923072b8
FG
54```
55
f2b60f7d 56`typeck_field_already_declared` is the slug from our example and is followed
923072b8
FG
57by the diagnostic message.
58
59Every field of the `SessionDiagnostic` which does not have an annotation is
60available in Fluent messages as a variable, like `field_name` in the example
61above. Fields can be annotated `#[skip_arg]` if this is undesired.
62
63Using the `#[primary_span]` attribute on a field (that has type `Span`)
64indicates the primary span of the diagnostic which will have the main message
65of the diagnostic.
66
67Diagnostics are more than just their primary message, they often include
68labels, notes, help messages and suggestions, all of which can also be
69specified on a `SessionDiagnostic`.
70
71`#[label]`, `#[help]` and `#[note]` can all be applied to fields which have the
72type `Span`. Applying any of these attributes will create the corresponding
73subdiagnostic with that `Span`. These attributes will look for their
74diagnostic message in a Fluent attribute attached to the primary Fluent
75message. In our example, `#[label]` will look for
f2b60f7d 76`typeck_field_already_declared.label` (which has the message "field already
923072b8
FG
77declared"). If there is more than one subdiagnostic of the same type, then
78these attributes can also take a value that is the attribute name to look for
f2b60f7d 79(e.g. `previous_decl_label` in our example).
923072b8
FG
80
81Other types have special behavior when used in a `SessionDiagnostic` derive:
82
83- Any attribute applied to an `Option<T>` and will only emit a
84 subdiagnostic if the option is `Some(..)`.
85- Any attribute applied to a `Vec<T>` will be repeated for each element of the
86 vector.
87
88`#[help]` and `#[note]` can also be applied to the struct itself, in which case
89they work exactly like when applied to fields except the subdiagnostic won't
90have a `Span`. These attributes can also be applied to fields of type `()` for
91the same effect, which when combined with the `Option` type can be used to
92represent optional `#[note]`/`#[help]` subdiagnostics.
93
94Suggestions can be emitted using one of four field attributes:
95
f2b60f7d
FG
96- `#[suggestion(slug, code = "...", applicability = "...")]`
97- `#[suggestion_hidden(slug, code = "...", applicability = "...")]`
98- `#[suggestion_short(slug, code = "...", applicability = "...")]`
99- `#[suggestion_verbose(slug, code = "...", applicability = "...")]`
923072b8
FG
100
101Suggestions must be applied on either a `Span` field or a `(Span,
f2b60f7d
FG
102MachineApplicability)` field. Similarly to other field attributes, the slug
103specifies the Fluent attribute with the message and defaults to the equivalent
104of `.suggestion`. `code` specifies the code that should be suggested as a
105replacement and is a format string (e.g. `{field_name}` would be replaced by
106the value of the `field_name` field of the struct), not a Fluent identifier.
107`applicability` can be used to specify the applicability in the attribute, it
108cannot be used when the field's type contains an `Applicability`.
923072b8
FG
109
110In the end, the `SessionDiagnostic` derive will generate an implementation of
111`SessionDiagnostic` that looks like the following:
112
113```rust,ignore
f2b60f7d 114impl SessionDiagnostic<'_> for FieldAlreadyDeclared {
923072b8 115 fn into_diagnostic(self, sess: &'_ rustc_session::Session) -> DiagnosticBuilder<'_> {
f2b60f7d 116 let mut diag = sess.struct_err(rustc_errors::fluent::typeck::field_already_declared);
923072b8
FG
117 diag.set_span(self.span);
118 diag.span_label(
119 self.span,
f2b60f7d 120 rustc_errors::fluent::typeck::label
923072b8
FG
121 );
122 diag.span_label(
123 self.prev_span,
f2b60f7d 124 rustc_errors::fluent::typeck::previous_decl_label
923072b8
FG
125 );
126 diag
127 }
128}
129```
130
131Now that we've defined our diagnostic, how do we [use it][use]? It's quite
132straightforward, just create an instance of the struct and pass it to
133`emit_err` (or `emit_warning`):
134
135```rust,ignore
136tcx.sess.emit_err(FieldAlreadyDeclared {
137 field_name: f.ident,
138 span: f.span,
139 prev_span,
140});
141```
142
143### Reference
f2b60f7d
FG
144`#[derive(SessionDiagnostic)]` and `#[derive(LintDiagnostic)]` support the
145following attributes:
923072b8 146
f2b60f7d 147- `#[diag(slug, code = "...")]`
923072b8
FG
148 - _Applied to struct._
149 - _Mandatory_
f2b60f7d 150 - Defines the text and error code to be associated with the diagnostic.
064997fb 151 - Slug (_Mandatory_)
923072b8
FG
152 - Uniquely identifies the diagnostic and corresponds to its Fluent message,
153 mandatory.
064997fb
FG
154 - A path to an item in `rustc_errors::fluent`. Always in a module starting
155 with a Fluent resource name (which is typically the name of the crate
156 that the diagnostic is from), e.g.
157 `rustc_errors::fluent::typeck::field_already_declared`
158 (`rustc_errors::fluent` is implicit in the attribute, so just
159 `typeck::field_already_declared`).
160 - See [translation documentation](./translation.md).
161 - `code = "..."` (_Optional_)
162 - Specifies the error code.
f2b60f7d 163- `#[note]` or `#[note(slug)]` (_Optional_)
923072b8
FG
164 - _Applied to struct or `Span`/`()` fields._
165 - Adds a note subdiagnostic.
f2b60f7d
FG
166 - Value is a path to an item in `rustc_errors::fluent` for the note's
167 message.
168 - Defaults to equivalent of `.note`.
923072b8 169 - If applied to a `Span` field, creates a spanned note.
f2b60f7d 170- `#[help]` or `#[help(slug)]` (_Optional_)
923072b8
FG
171 - _Applied to struct or `Span`/`()` fields._
172 - Adds a help subdiagnostic.
f2b60f7d
FG
173 - Value is a path to an item in `rustc_errors::fluent` for the note's
174 message.
175 - Defaults to equivalent of `.help`.
923072b8 176 - If applied to a `Span` field, creates a spanned help.
f2b60f7d 177- `#[label]` or `#[label(slug)]` (_Optional_)
923072b8
FG
178 - _Applied to `Span` fields._
179 - Adds a label subdiagnostic.
f2b60f7d
FG
180 - Value is a path to an item in `rustc_errors::fluent` for the note's
181 message.
182 - Defaults to equivalent of `.label`.
183- `#[warn_]` or `#[warn_(slug)]` (_Optional_)
184 - _Applied to `Span` fields._
185 - Adds a warning subdiagnostic.
186 - Value is a path to an item in `rustc_errors::fluent` for the note's
187 message.
188 - Defaults to equivalent of `.warn`.
189- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]`
923072b8
FG
190 (_Optional_)
191 - _Applied to `(Span, MachineApplicability)` or `Span` fields._
192 - Adds a suggestion subdiagnostic.
f2b60f7d
FG
193 - Slug (_Mandatory_)
194 - A path to an item in `rustc_errors::fluent`. Always in a module starting
195 with a Fluent resource name (which is typically the name of the crate
196 that the diagnostic is from), e.g.
197 `rustc_errors::fluent::typeck::field_already_declared`
198 (`rustc_errors::fluent` is implicit in the attribute, so just
199 `typeck::field_already_declared`). Fluent attributes for all messages
200 exist as top-level items in that module (so `typeck_message.attr` is just
201 `typeck::attr`).
202 - See [translation documentation](./translation.md).
203 - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or
204 - `.suggestion` in Fluent).
923072b8
FG
205 - `code = "..."` (_Mandatory_)
206 - Value is a format string indicating the code to be suggested as a
207 replacement.
208 - `applicability = "..."` (_Optional_)
209 - String which must be one of `machine-applicable`, `maybe-incorrect`,
210 `has-placeholders` or `unspecified`.
211- `#[subdiagnostic]`
212 - _Applied to a type that implements `AddToDiagnostic` (from
213 `#[derive(SessionSubdiagnostic)]`)._
214 - Adds the subdiagnostic represented by the subdiagnostic struct.
215- `#[primary_span]` (_Optional_)
f2b60f7d 216 - _Applied to `Span` fields on `SessionSubdiagnostic`s. Not used for `LintDiagnostic`s._
923072b8
FG
217 - Indicates the primary span of the diagnostic.
218- `#[skip_arg]` (_Optional_)
219 - _Applied to any field._
220 - Prevents the field from being provided as a diagnostic argument.
221
222## `#[derive(SessionSubdiagnostic)]`
223It is common in the compiler to write a function that conditionally adds a
224specific subdiagnostic to an error if it is applicable. Oftentimes these
225subdiagnostics could be represented using a diagnostic struct even if the
226overall diagnostic could not. In this circumstance, the `SessionSubdiagnostic`
227derive can be used to represent a partial diagnostic (e.g a note, label, help or
228suggestion) as a struct.
229
230Consider the [definition][subdiag_defn] of the "expected return type" label
231shown below:
232
233```rust
234#[derive(SessionSubdiagnostic)]
235pub enum ExpectedReturnTypeLabel<'tcx> {
064997fb 236 #[label(typeck::expected_default_return_type)]
923072b8
FG
237 Unit {
238 #[primary_span]
239 span: Span,
240 },
064997fb 241 #[label(typeck::expected_return_type)]
923072b8
FG
242 Other {
243 #[primary_span]
244 span: Span,
245 expected: Ty<'tcx>,
246 },
247}
248```
249
250Unlike `SessionDiagnostic`, `SessionSubdiagnostic` can be applied to structs or
251enums. Attributes that are placed on the type for structs are placed on each
252variants for enums (or vice versa). Each `SessionSubdiagnostic` should have one
253attribute applied to the struct or each variant, one of:
254
255- `#[label(..)]` for defining a label
256- `#[note(..)]` for defining a note
257- `#[help(..)]` for defining a help
258- `#[suggestion{,_hidden,_short,_verbose}(..)]` for defining a suggestion
259
064997fb
FG
260All of the above must provide a slug as the first positional argument (a path
261to an item in `rustc_errors::fluent::*`). A slug uniquely identifies the
262diagnostic and is also how the compiler knows what error message to emit (in
263the default locale of the compiler, or in the locale requested by the user).
264See [translation documentation](./translation.md) to learn more about how
265translatable error messages are written and how slug items are generated.
923072b8
FG
266
267In our example, the Fluent message for the "expected return type" label
268looks like this:
269
270```fluent
f2b60f7d 271typeck_expected_default_return_type = expected `()` because of default return type
923072b8 272
f2b60f7d 273typeck_expected_return_type = expected `{$expected}` because of return type
923072b8
FG
274```
275
276Using the `#[primary_span]` attribute on a field (with type `Span`) will denote
277the primary span of the subdiagnostic. A primary span is only necessary for a
278label or suggestion, which can not be spanless.
279
280Every field of the type/variant which does not have an annotation is available
281in Fluent messages as a variable. Fields can be annotated `#[skip_arg]` if this
282is undesired.
283
284Like `SessionDiagnostic`, `SessionSubdiagnostic` supports `Option<T>` and
285`Vec<T>` fields.
286
287Suggestions can be emitted using one of four attributes on the type/variant:
288
f2b60f7d
FG
289- `#[suggestion(..., code = "...", applicability = "...")]`
290- `#[suggestion_hidden(..., code = "...", applicability = "...")]`
291- `#[suggestion_short(..., code = "...", applicability = "...")]`
292- `#[suggestion_verbose(..., code = "...", applicability = "...")]`
923072b8
FG
293
294Suggestions require `#[primary_span]` be set on a field and can have the
295following sub-attributes:
296
f2b60f7d
FG
297- The first positional argument specifies the path to a item in
298 `rustc_errors::fluent` corresponding to the Fluent attribute with the message
299 and defaults to the equivalent of `.suggestion`.
923072b8
FG
300- `code` specifies the code that should be suggested as a replacement and is a
301 format string (e.g. `{field_name}` would be replaced by the value of the
302 `field_name` field of the struct), not a Fluent identifier.
303- `applicability` can be used to specify the applicability in the attribute, it
304 cannot be used when the field's type contains an `Applicability`.
305
306Applicabilities can also be specified as a field (of type `Applicability`)
307using the `#[applicability]` attribute.
308
309In the end, the `SessionSubdiagnostic` derive will generate an implementation
310of `SessionSubdiagnostic` that looks like the following:
311
312```rust
313impl<'tcx> AddToDiagnostic for ExpectedReturnTypeLabel<'tcx> {
314 fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
315 use rustc_errors::{Applicability, IntoDiagnosticArg};
316 match self {
317 ExpectedReturnTypeLabel::Unit { span } => {
f2b60f7d 318 diag.span_label(span, rustc_errors::fluent::typeck::expected_default_return_type)
923072b8
FG
319 }
320 ExpectedReturnTypeLabel::Other { span, expected } => {
321 diag.set_arg("expected", expected);
f2b60f7d 322 diag.span_label(span, rustc_errors::fluent::typeck::expected_return_type)
923072b8
FG
323 }
324
325 }
326 }
327}
328```
329
330Once defined, a subdiagnostic can be used by passing it to the `subdiagnostic`
331function ([example][subdiag_use_1] and [example][subdiag_use_2]) on a
332diagnostic or by assigning it to a `#[subdiagnostic]`-annotated field of a
333diagnostic struct.
334
335### Reference
336`#[derive(SessionSubdiagnostic)]` supports the following attributes:
337
064997fb 338- `#[label(slug)]`, `#[help(slug)]` or `#[note(slug)]`
923072b8
FG
339 - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._
340 - _Mandatory_
341 - Defines the type to be representing a label, help or note.
064997fb 342 - Slug (_Mandatory_)
923072b8
FG
343 - Uniquely identifies the diagnostic and corresponds to its Fluent message,
344 mandatory.
064997fb
FG
345 - A path to an item in `rustc_errors::fluent`. Always in a module starting
346 with a Fluent resource name (which is typically the name of the crate
347 that the diagnostic is from), e.g.
348 `rustc_errors::fluent::typeck::field_already_declared`
349 (`rustc_errors::fluent` is implicit in the attribute, so just
350 `typeck::field_already_declared`).
351 - See [translation documentation](./translation.md).
f2b60f7d 352- `#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]`
923072b8
FG
353 - _Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes._
354 - _Mandatory_
355 - Defines the type to be representing a suggestion.
f2b60f7d
FG
356 - Slug (_Mandatory_)
357 - A path to an item in `rustc_errors::fluent`. Always in a module starting
358 with a Fluent resource name (which is typically the name of the crate
359 that the diagnostic is from), e.g.
360 `rustc_errors::fluent::typeck::field_already_declared`
361 (`rustc_errors::fluent` is implicit in the attribute, so just
362 `typeck::field_already_declared`). Fluent attributes for all messages
363 exist as top-level items in that module (so `typeck_message.attr` is just
364 `typeck::attr`).
365 - See [translation documentation](./translation.md).
366 - Defaults to `rustc_errors::fluent::_subdiag::suggestion` (or
367 - `.suggestion` in Fluent).
923072b8
FG
368 - `code = "..."` (_Mandatory_)
369 - Value is a format string indicating the code to be suggested as a
370 replacement.
371 - `applicability = "..."` (_Optional_)
372 - _Mutually exclusive with `#[applicability]` on a field._
373 - Value is the applicability of the suggestion.
374 - String which must be one of:
375 - `machine-applicable`
376 - `maybe-incorrect`
377 - `has-placeholders`
378 - `unspecified`
379- `#[primary_span]` (_Mandatory_ for labels and suggestions; _optional_ otherwise)
380 - _Applied to `Span` fields._
381 - Indicates the primary span of the subdiagnostic.
382- `#[applicability]` (_Optional_; only applicable to suggestions)
383 - _Applied to `Applicability` fields._
384 - Indicates the applicability of the suggestion.
385- `#[skip_arg]` (_Optional_)
386 - _Applied to any field._
387 - Prevents the field from being provided as a diagnostic argument.
388
389[defn]: https://github.com/rust-lang/rust/blob/bbe9d27b8ff36da56638aa43d6d0cdfdf89a4e57/compiler/rustc_typeck/src/errors.rs#L65-L74
390[use]: https://github.com/rust-lang/rust/blob/eb82facb1626166188d49599a3313fc95201f556/compiler/rustc_typeck/src/collect.rs#L981-L985
391
392[subdiag_defn]: https://github.com/rust-lang/rust/blob/e70c60d34b9783a2fd3171d88d248c2e0ec8ecdd/compiler/rustc_typeck/src/errors.rs#L220-L233
393[subdiag_use_1]: https://github.com/rust-lang/rust/blob/e70c60d34b9783a2fd3171d88d248c2e0ec8ecdd/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs#L556-L560
394[subdiag_use_2]: https://github.com/rust-lang/rust/blob/e70c60d34b9783a2fd3171d88d248c2e0ec8ecdd/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs#L575-L579