rustc_macros/diagnostics/
mod.rs

1mod diagnostic;
2mod diagnostic_builder;
3mod error;
4mod subdiagnostic;
5mod utils;
6
7use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
8use proc_macro2::TokenStream;
9use subdiagnostic::SubdiagnosticDerive;
10use synstructure::Structure;
11
12/// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
13/// independent from the actual diagnostics emitting code.
14///
15/// ```ignore (rust)
16/// # extern crate rustc_errors;
17/// # use rustc_errors::Applicability;
18/// # extern crate rustc_span;
19/// # use rustc_span::{Ident, Span};
20/// # extern crate rust_middle;
21/// # use rustc_middle::ty::Ty;
22/// #[derive(Diagnostic)]
23/// #[diag(borrowck_move_out_of_borrow, code = E0505)]
24/// pub struct MoveOutOfBorrowError<'tcx> {
25///     pub name: Ident,
26///     pub ty: Ty<'tcx>,
27///     #[primary_span]
28///     #[label]
29///     pub span: Span,
30///     #[label(first_borrow_label)]
31///     pub first_borrow_span: Span,
32///     #[suggestion(code = "{name}.clone()")]
33///     pub clone_sugg: Option<(Span, Applicability)>
34/// }
35/// ```
36///
37/// ```fluent
38/// move_out_of_borrow = cannot move out of {$name} because it is borrowed
39///     .label = cannot move out of borrow
40///     .first_borrow_label = `{$ty}` first borrowed here
41///     .suggestion = consider cloning here
42/// ```
43///
44/// Then, later, to emit the error:
45///
46/// ```ignore (rust)
47/// sess.emit_err(MoveOutOfBorrowError {
48///     expected,
49///     actual,
50///     span,
51///     first_borrow_span,
52///     clone_sugg: Some(suggestion, Applicability::MachineApplicable),
53/// });
54/// ```
55///
56/// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`:
57/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
58pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
59    s.underscore_const(true);
60    DiagnosticDerive::new(s).into_tokens()
61}
62
63/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
64/// independent from the actual lint emitting code.
65///
66/// ```ignore (rust)
67/// #[derive(LintDiagnostic)]
68/// #[diag(lint_atomic_ordering_invalid_fail_success)]
69/// pub struct AtomicOrderingInvalidLint {
70///     method: Symbol,
71///     success_ordering: Symbol,
72///     fail_ordering: Symbol,
73///     #[label(fail_label)]
74///     fail_order_arg_span: Span,
75///     #[label(success_label)]
76///     #[suggestion(
77///         code = "std::sync::atomic::Ordering::{success_suggestion}",
78///         applicability = "maybe-incorrect"
79///     )]
80///     success_order_arg_span: Span,
81/// }
82/// ```
83///
84/// ```fluent
85/// lint_atomic_ordering_invalid_fail_success = `{$method}`'s success ordering must be at least as strong as its failure ordering
86///     .fail_label = `{$fail_ordering}` failure ordering
87///     .success_label = `{$success_ordering}` success ordering
88///     .suggestion = consider using `{$success_suggestion}` success ordering instead
89/// ```
90///
91/// Then, later, to emit the error:
92///
93/// ```ignore (rust)
94/// cx.emit_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
95///     method,
96///     success_ordering,
97///     fail_ordering,
98///     fail_order_arg_span,
99///     success_order_arg_span,
100/// });
101/// ```
102///
103/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
104/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
105pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
106    s.underscore_const(true);
107    LintDiagnosticDerive::new(s).into_tokens()
108}
109
110/// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and
111/// suggestions to be specified as a structs or enums, independent from the actual diagnostics
112/// emitting code or diagnostic derives.
113///
114/// ```ignore (rust)
115/// #[derive(Subdiagnostic)]
116/// pub enum ExpectedIdentifierLabel<'tcx> {
117///     #[label(expected_identifier)]
118///     WithoutFound {
119///         #[primary_span]
120///         span: Span,
121///     }
122///     #[label(expected_identifier_found)]
123///     WithFound {
124///         #[primary_span]
125///         span: Span,
126///         found: String,
127///     }
128/// }
129///
130/// #[derive(Subdiagnostic)]
131/// #[suggestion(style = "verbose",parser::raw_identifier)]
132/// pub struct RawIdentifierSuggestion<'tcx> {
133///     #[primary_span]
134///     span: Span,
135///     #[applicability]
136///     applicability: Applicability,
137///     ident: Ident,
138/// }
139/// ```
140///
141/// ```fluent
142/// parser_expected_identifier = expected identifier
143///
144/// parser_expected_identifier_found = expected identifier, found {$found}
145///
146/// parser_raw_identifier = escape `{$ident}` to use it as an identifier
147/// ```
148///
149/// Then, later, to add the subdiagnostic:
150///
151/// ```ignore (rust)
152/// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
153///
154/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
155/// ```
156pub(super) fn subdiagnostic_derive(mut s: Structure<'_>) -> TokenStream {
157    s.underscore_const(true);
158    SubdiagnosticDerive::new().into_tokens(s)
159}