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}