1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! Facility for stacking and emitting multiple errors. //! //! [`abort!`] macro stops a proc-macro *right away*, much like in a panic-like //! fashion. But sometimes you *do not* want to stop right there, for example you're //! processing a list of attributes and want to *emit* a separate error for every //! mis-built attribute. //! //! The [`emit_error!`] and [`emit_call_site_error!`] macros are just for it! use crate::{check_correctness, AbortNow, MacroError}; use std::cell::RefCell; thread_local! { static ERR_STORAGE: RefCell<Vec<MacroError>> = RefCell::new(Vec::new()); } /// Emit an error while not aborting the proc-macro right away. /// /// The emitted errors will be converted to a `TokenStream` sequence /// of `compile_error!` invocations after the execution hits the end /// of the function marked with `[proc_macro_error]` or the lambda passed to [`entry_point`]. /// /// # Syntax /// /// The same as [`abort!`]. /// /// # Note: /// If a panic occurs somewhere in your macro no errors will be shown. #[macro_export] macro_rules! emit_error { ($($tts:tt)*) => {{ $crate::macro_error!($($tts)*).emit() }}; } /// Shortcut for `emit_error!(Span::call_site(), msg...)`. This macro /// is still preferable over plain panic, see [Motivation](#motivation) #[macro_export] macro_rules! emit_call_site_error { ($($tts:tt)*) => {{ let span = $crate::proc_macro2::Span::call_site(); $crate::macro_error!(span, $($tts)*).emit() }}; } /// Abort macro execution and display all the emitted errors, if any. /// /// Does nothing if no errors were emitted. pub fn abort_if_dirty() { check_correctness(); ERR_STORAGE.with(|storage| { if !storage.borrow().is_empty() { abort_now() } }); } /// Clear the global error storage, returning the errors contained. pub(crate) fn cleanup() -> Vec<MacroError> { ERR_STORAGE.with(|storage| storage.replace(Vec::new())) } /// Abort right now. pub(crate) fn abort_now() -> ! { check_correctness(); panic!(AbortNow) } /// Push the error into the global error storage. /// /// **Not public API.** #[doc(hidden)] pub fn push_error(error: MacroError) { check_correctness(); ERR_STORAGE.with(|storage| storage.borrow_mut().push(error)) }