Home Explore Blog CI



rustc

1st chunk of `src/diagnostics/diagnostic-structs.md`
68b7b39e05ffc89b39deb68b843fa4af3669d9f7f9ee87de0000000100000fe6
# Diagnostic and subdiagnostic structs
rustc has three diagnostic traits that can be used to create diagnostics:
`Diagnostic`, `LintDiagnostic`, and `Subdiagnostic`. For simple diagnostics,
instead of using the `Diag` API to create and emit diagnostics,
derived impls can be used. They are only suitable for simple diagnostics that
don't require much logic in deciding whether or not to add additional
subdiagnostics.

Such diagnostic can be translated into
different languages and each has a slug that uniquely identifies the
diagnostic.

## `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]`

Consider the [definition][defn] of the "field already declared" diagnostic
shown below:

```rust,ignore
#[derive(Diagnostic)]
#[diag(hir_analysis_field_already_declared, code = E0124)]
pub struct FieldAlreadyDeclared {
    pub field_name: Ident,
    #[primary_span]
    #[label]
    pub span: Span,
    #[label(previous_decl_label)]
    pub prev_span: Span,
}
```

`Diagnostic` can only be derived on structs and enums. 
Attributes that are placed on the type for structs are placed on each 
variants for enums (or vice versa). Each `Diagnostic` has to have one
attribute, `#[diag(...)]`, applied to the struct or each enum variant.

If an error has an error code (e.g. "E0624"), then that can be specified using
the `code` sub-attribute. Specifying a `code` isn't mandatory, but if you are
porting a diagnostic that uses `Diag` to use `Diagnostic`
then you should keep the code if there was one.

`#[diag(..)]` must provide a slug as the first positional argument (a path to an
item in `rustc_errors::fluent::*`). A slug uniquely identifies the diagnostic
and is also how the compiler knows what error message to emit (in the default
locale of the compiler, or in the locale requested by the user). See
[translation documentation](./translation.md) to learn more about how
translatable error messages are written and how slug items are generated.

In our example, the Fluent message for the "field already declared" diagnostic
looks like this:

```fluent
hir_analysis_field_already_declared =
    field `{$field_name}` is already declared
    .label = field already declared
    .previous_decl_label = `{$field_name}` first declared here
```

`hir_analysis_field_already_declared` is the slug from our example and is followed
by the diagnostic message.

Every field of the `Diagnostic` which does not have an annotation is
available in Fluent messages as a variable, like `field_name` in the example
above. Fields can be annotated `#[skip_arg]` if this is undesired.

Using the `#[primary_span]` attribute on a field (that has type `Span`)
indicates the primary span of the diagnostic which will have the main message
of the diagnostic.

Diagnostics are more than just their primary message, they often include
labels, notes, help messages and suggestions, all of which can also be
specified on a `Diagnostic`.

`#[label]`, `#[help]`, `#[warning]` and `#[note]` can all be applied to fields which have the
type `Span`. Applying any of these attributes will create the corresponding
subdiagnostic with that `Span`. These attributes will look for their
diagnostic message in a Fluent attribute attached to the primary Fluent
message. In our example, `#[label]` will look for
`hir_analysis_field_already_declared.label` (which has the message "field already
declared"). If there is more than one subdiagnostic of the same type, then
these attributes can also take a value that is the attribute name to look for
(e.g. `previous_decl_label` in our example).

Other types have special behavior when used in a `Diagnostic` derive:

- Any attribute applied to an `Option<T>` will only emit a
  subdiagnostic if the option is `Some(..)`.
- Any attribute applied to a `Vec<T>` will be repeated for each element of the
  vector.

`#[help]`, `#[warning]` and `#[note]` can also be applied to the struct itself, in which case
they work exactly like when applied to fields except the subdiagnostic won't
have a `Span`. These attributes can also be applied to fields of type `()` for

Title: Diagnostic and Subdiagnostic Structs in rustc
Summary
This section describes how to define diagnostics in rustc using the `Diagnostic`, `LintDiagnostic`, and `Subdiagnostic` traits and the `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` attributes. It explains how to specify error codes, slugs, primary spans, labels, notes, help messages, and suggestions within a diagnostic. It also covers how fields in a `Diagnostic` struct are used in Fluent messages and how attributes like `#[primary_span]`, `#[label]`, `#[help]`, `#[warning]`, and `#[note]` are used to create subdiagnostics.