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}