]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_macros/src/diagnostics/error.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_macros / src / diagnostics / error.rs
1 use proc_macro::{Diagnostic, Level, MultiSpan};
2 use proc_macro2::TokenStream;
3 use quote::quote;
4 use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta};
5
6 #[derive(Debug)]
7 pub(crate) enum SessionDiagnosticDeriveError {
8 SynError(SynError),
9 ErrorHandled,
10 }
11
12 impl SessionDiagnosticDeriveError {
13 pub(crate) fn to_compile_error(self) -> TokenStream {
14 match self {
15 SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(),
16 SessionDiagnosticDeriveError::ErrorHandled => {
17 // Return ! to avoid having to create a blank DiagnosticBuilder to return when an
18 // error has already been emitted to the compiler.
19 quote! {
20 { unreachable!(); }
21 }
22 }
23 }
24 }
25 }
26
27 impl From<SynError> for SessionDiagnosticDeriveError {
28 fn from(e: SynError) -> Self {
29 SessionDiagnosticDeriveError::SynError(e)
30 }
31 }
32
33 /// Helper function for use with `throw_*` macros - constraints `$f` to an `impl FnOnce`.
34 pub(crate) fn _throw_err(
35 diag: Diagnostic,
36 f: impl FnOnce(Diagnostic) -> Diagnostic,
37 ) -> SessionDiagnosticDeriveError {
38 f(diag).emit();
39 SessionDiagnosticDeriveError::ErrorHandled
40 }
41
42 /// Returns an error diagnostic on span `span` with msg `msg`.
43 pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
44 Diagnostic::spanned(span, Level::Error, msg)
45 }
46
47 /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
48 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
49 ///
50 /// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
51 macro_rules! throw_span_err {
52 ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
53 ($span:expr, $msg:expr, $f:expr) => {{
54 let diag = span_err($span, $msg);
55 return Err(crate::diagnostics::error::_throw_err(diag, $f));
56 }};
57 }
58
59 pub(crate) use throw_span_err;
60
61 /// Returns an error diagnostic for an invalid attribute.
62 pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
63 let span = attr.span().unwrap();
64 let name = attr.path.segments.last().unwrap().ident.to_string();
65 let name = name.as_str();
66
67 match meta {
68 Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", name)),
69 Meta::NameValue(_) => {
70 span_err(span, &format!("`#[{} = ...]` is not a valid attribute", name))
71 }
72 Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", name)),
73 }
74 }
75
76 /// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration
77 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
78 ///
79 /// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
80 macro_rules! throw_invalid_attr {
81 ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }};
82 ($attr:expr, $meta:expr, $f:expr) => {{
83 let diag = crate::diagnostics::error::invalid_attr($attr, $meta);
84 return Err(crate::diagnostics::error::_throw_err(diag, $f));
85 }};
86 }
87
88 pub(crate) use throw_invalid_attr;
89
90 /// Returns an error diagnostic for an invalid nested attribute.
91 pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diagnostic {
92 let name = attr.path.segments.last().unwrap().ident.to_string();
93 let name = name.as_str();
94
95 let span = nested.span().unwrap();
96 let meta = match nested {
97 syn::NestedMeta::Meta(meta) => meta,
98 syn::NestedMeta::Lit(_) => {
99 return span_err(span, &format!("`#[{}(\"...\")]` is not a valid attribute", name));
100 }
101 };
102
103 let span = meta.span().unwrap();
104 let nested_name = meta.path().segments.last().unwrap().ident.to_string();
105 let nested_name = nested_name.as_str();
106 match meta {
107 Meta::NameValue(..) => span_err(
108 span,
109 &format!("`#[{}({} = ...)]` is not a valid attribute", name, nested_name),
110 ),
111 Meta::Path(..) => {
112 span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, nested_name))
113 }
114 Meta::List(..) => {
115 span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, nested_name))
116 }
117 }
118 }
119
120 /// Emit a error diagnostic for an invalid nested attribute (optionally performing additional
121 /// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
122 ///
123 /// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
124 macro_rules! throw_invalid_nested_attr {
125 ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }};
126 ($attr:expr, $nested_attr:expr, $f:expr) => {{
127 let diag = crate::diagnostics::error::invalid_nested_attr($attr, $nested_attr);
128 return Err(crate::diagnostics::error::_throw_err(diag, $f));
129 }};
130 }
131
132 pub(crate) use throw_invalid_nested_attr;