]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_macros/src/diagnostics/error.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_macros / src / diagnostics / error.rs
CommitLineData
04454e1e
FG
1use proc_macro::{Diagnostic, Level, MultiSpan};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta};
5
6#[derive(Debug)]
064997fb 7pub(crate) enum DiagnosticDeriveError {
04454e1e
FG
8 SynError(SynError),
9 ErrorHandled,
10}
11
064997fb 12impl DiagnosticDeriveError {
04454e1e
FG
13 pub(crate) fn to_compile_error(self) -> TokenStream {
14 match self {
064997fb
FG
15 DiagnosticDeriveError::SynError(e) => e.to_compile_error(),
16 DiagnosticDeriveError::ErrorHandled => {
04454e1e
FG
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
064997fb 27impl From<SynError> for DiagnosticDeriveError {
04454e1e 28 fn from(e: SynError) -> Self {
064997fb 29 DiagnosticDeriveError::SynError(e)
04454e1e
FG
30 }
31}
32
33/// Helper function for use with `throw_*` macros - constraints `$f` to an `impl FnOnce`.
34pub(crate) fn _throw_err(
35 diag: Diagnostic,
36 f: impl FnOnce(Diagnostic) -> Diagnostic,
064997fb 37) -> DiagnosticDeriveError {
04454e1e 38 f(diag).emit();
064997fb
FG
39 DiagnosticDeriveError::ErrorHandled
40}
41
42/// Helper function for printing `syn::Path` - doesn't handle arguments in paths and these are
43/// unlikely to come up much in use of the macro.
44fn path_to_string(path: &syn::Path) -> String {
45 let mut out = String::new();
46 for (i, segment) in path.segments.iter().enumerate() {
47 if i > 0 || path.leading_colon.is_some() {
48 out.push_str("::");
49 }
50 out.push_str(&segment.ident.to_string());
51 }
52 out
04454e1e
FG
53}
54
55/// Returns an error diagnostic on span `span` with msg `msg`.
56pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
57 Diagnostic::spanned(span, Level::Error, msg)
58}
59
60/// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
61/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
62///
064997fb 63/// For methods that return a `Result<_, DiagnosticDeriveError>`:
04454e1e
FG
64macro_rules! throw_span_err {
65 ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
66 ($span:expr, $msg:expr, $f:expr) => {{
67 let diag = span_err($span, $msg);
68 return Err(crate::diagnostics::error::_throw_err(diag, $f));
69 }};
70}
71
72pub(crate) use throw_span_err;
73
74/// Returns an error diagnostic for an invalid attribute.
75pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
76 let span = attr.span().unwrap();
064997fb 77 let path = path_to_string(&attr.path);
04454e1e 78 match meta {
9c376795 79 Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")),
04454e1e 80 Meta::NameValue(_) => {
9c376795 81 span_err(span, &format!("`#[{path} = ...]` is not a valid attribute"))
04454e1e 82 }
9c376795 83 Meta::List(_) => span_err(span, &format!("`#[{path}(...)]` is not a valid attribute")),
04454e1e
FG
84 }
85}
86
487cf647 87/// Emit an error diagnostic for an invalid attribute (optionally performing additional decoration
04454e1e
FG
88/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
89///
064997fb 90/// For methods that return a `Result<_, DiagnosticDeriveError>`:
04454e1e
FG
91macro_rules! throw_invalid_attr {
92 ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }};
93 ($attr:expr, $meta:expr, $f:expr) => {{
94 let diag = crate::diagnostics::error::invalid_attr($attr, $meta);
95 return Err(crate::diagnostics::error::_throw_err(diag, $f));
96 }};
97}
98
99pub(crate) use throw_invalid_attr;
100
101/// Returns an error diagnostic for an invalid nested attribute.
102pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diagnostic {
103 let name = attr.path.segments.last().unwrap().ident.to_string();
104 let name = name.as_str();
105
106 let span = nested.span().unwrap();
107 let meta = match nested {
108 syn::NestedMeta::Meta(meta) => meta,
109 syn::NestedMeta::Lit(_) => {
9c376795 110 return span_err(span, &format!("`#[{name}(\"...\")]` is not a valid attribute"));
04454e1e
FG
111 }
112 };
113
114 let span = meta.span().unwrap();
064997fb 115 let path = path_to_string(meta.path());
04454e1e 116 match meta {
064997fb 117 Meta::NameValue(..) => {
9c376795 118 span_err(span, &format!("`#[{name}({path} = ...)]` is not a valid attribute"))
04454e1e 119 }
9c376795 120 Meta::Path(..) => span_err(span, &format!("`#[{name}({path})]` is not a valid attribute")),
04454e1e 121 Meta::List(..) => {
9c376795 122 span_err(span, &format!("`#[{name}({path}(...))]` is not a valid attribute"))
04454e1e
FG
123 }
124 }
125}
126
487cf647 127/// Emit an error diagnostic for an invalid nested attribute (optionally performing additional
04454e1e
FG
128/// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
129///
064997fb 130/// For methods that return a `Result<_, DiagnosticDeriveError>`:
04454e1e
FG
131macro_rules! throw_invalid_nested_attr {
132 ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }};
133 ($attr:expr, $nested_attr:expr, $f:expr) => {{
134 let diag = crate::diagnostics::error::invalid_nested_attr($attr, $nested_attr);
135 return Err(crate::diagnostics::error::_throw_err(diag, $f));
136 }};
137}
138
139pub(crate) use throw_invalid_nested_attr;