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(s: Structure<'_>) -> TokenStream {
59    DiagnosticDerive::new(s).into_tokens()
60}
61
62/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
63/// independent from the actual lint emitting code.
64///
65/// ```ignore (rust)
66/// #[derive(LintDiagnostic)]
67/// #[diag(lint_atomic_ordering_invalid_fail_success)]
68/// pub struct AtomicOrderingInvalidLint {
69///     method: Symbol,
70///     success_ordering: Symbol,
71///     fail_ordering: Symbol,
72///     #[label(fail_label)]
73///     fail_order_arg_span: Span,
74///     #[label(success_label)]
75///     #[suggestion(
76///         code = "std::sync::atomic::Ordering::{success_suggestion}",
77///         applicability = "maybe-incorrect"
78///     )]
79///     success_order_arg_span: Span,
80/// }
81/// ```
82///
83/// ```fluent
84/// lint_atomic_ordering_invalid_fail_success = `{$method}`'s success ordering must be at least as strong as its failure ordering
85///     .fail_label = `{$fail_ordering}` failure ordering
86///     .success_label = `{$success_ordering}` success ordering
87///     .suggestion = consider using `{$success_suggestion}` success ordering instead
88/// ```
89///
90/// Then, later, to emit the error:
91///
92/// ```ignore (rust)
93/// cx.emit_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
94///     method,
95///     success_ordering,
96///     fail_ordering,
97///     fail_order_arg_span,
98///     success_order_arg_span,
99/// });
100/// ```
101///
102/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
103/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
104pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
105    LintDiagnosticDerive::new(s).into_tokens()
106}
107
108/// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and
109/// suggestions to be specified as a structs or enums, independent from the actual diagnostics
110/// emitting code or diagnostic derives.
111///
112/// ```ignore (rust)
113/// #[derive(Subdiagnostic)]
114/// pub enum ExpectedIdentifierLabel<'tcx> {
115///     #[label(expected_identifier)]
116///     WithoutFound {
117///         #[primary_span]
118///         span: Span,
119///     }
120///     #[label(expected_identifier_found)]
121///     WithFound {
122///         #[primary_span]
123///         span: Span,
124///         found: String,
125///     }
126/// }
127///
128/// #[derive(Subdiagnostic)]
129/// #[suggestion(style = "verbose",parser::raw_identifier)]
130/// pub struct RawIdentifierSuggestion<'tcx> {
131///     #[primary_span]
132///     span: Span,
133///     #[applicability]
134///     applicability: Applicability,
135///     ident: Ident,
136/// }
137/// ```
138///
139/// ```fluent
140/// parser_expected_identifier = expected identifier
141///
142/// parser_expected_identifier_found = expected identifier, found {$found}
143///
144/// parser_raw_identifier = escape `{$ident}` to use it as an identifier
145/// ```
146///
147/// Then, later, to add the subdiagnostic:
148///
149/// ```ignore (rust)
150/// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
151///
152/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
153/// ```
154pub(super) fn subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
155    SubdiagnosticDerive::new().into_tokens(s)
156}