rustc_macros/diagnostics/
error.rs
1use proc_macro::{Diagnostic, Level, MultiSpan};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::spanned::Spanned;
5use syn::{Attribute, Error as SynError, Meta};
6
7#[derive(Debug)]
8pub(crate) enum DiagnosticDeriveError {
9 SynError(SynError),
10 ErrorHandled,
11}
12
13impl DiagnosticDeriveError {
14 pub(crate) fn to_compile_error(self) -> TokenStream {
15 match self {
16 DiagnosticDeriveError::SynError(e) => e.to_compile_error(),
17 DiagnosticDeriveError::ErrorHandled => {
18 quote! {
21 { unreachable!(); }
22 }
23 }
24 }
25 }
26}
27
28impl From<SynError> for DiagnosticDeriveError {
29 fn from(e: SynError) -> Self {
30 DiagnosticDeriveError::SynError(e)
31 }
32}
33
34pub(crate) fn _throw_err(
36 diag: Diagnostic,
37 f: impl FnOnce(Diagnostic) -> Diagnostic,
38) -> DiagnosticDeriveError {
39 f(diag).emit();
40 DiagnosticDeriveError::ErrorHandled
41}
42
43fn path_to_string(path: &syn::Path) -> String {
46 let mut out = String::new();
47 for (i, segment) in path.segments.iter().enumerate() {
48 if i > 0 || path.leading_colon.is_some() {
49 out.push_str("::");
50 }
51 out.push_str(&segment.ident.to_string());
52 }
53 out
54}
55
56#[must_use]
58pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic {
59 Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into()))
60}
61
62macro_rules! throw_span_err {
67 ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
68 ($span:expr, $msg:expr, $f:expr) => {{
69 let diag = span_err($span, $msg);
70 return Err(crate::diagnostics::error::_throw_err(diag, $f));
71 }};
72}
73
74pub(crate) use throw_span_err;
75
76pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic {
78 let span = attr.span().unwrap();
79 let path = path_to_string(attr.path());
80 match attr.meta {
81 Meta::Path(_) => span_err(span, format!("`#[{path}]` is not a valid attribute")),
82 Meta::NameValue(_) => span_err(span, format!("`#[{path} = ...]` is not a valid attribute")),
83 Meta::List(_) => span_err(span, format!("`#[{path}(...)]` is not a valid attribute")),
84 }
85}
86
87macro_rules! throw_invalid_attr {
92 ($attr:expr) => {{ throw_invalid_attr!($attr, |diag| diag) }};
93 ($attr:expr, $f:expr) => {{
94 let diag = crate::diagnostics::error::invalid_attr($attr);
95 return Err(crate::diagnostics::error::_throw_err(diag, $f));
96 }};
97}
98
99pub(crate) use throw_invalid_attr;