diff options
Diffstat (limited to 'proc-macro-error/proc-macro-error/src')
-rw-r--r-- | proc-macro-error/proc-macro-error/src/dummy.rs | 136 | ||||
-rw-r--r-- | proc-macro-error/proc-macro-error/src/lib.rs | 514 | ||||
-rw-r--r-- | proc-macro-error/proc-macro-error/src/macros.rs | 257 | ||||
-rw-r--r-- | proc-macro-error/proc-macro-error/src/nightly.rs | 49 | ||||
-rw-r--r-- | proc-macro-error/proc-macro-error/src/stable.rs | 26 |
5 files changed, 0 insertions, 982 deletions
diff --git a/proc-macro-error/proc-macro-error/src/dummy.rs b/proc-macro-error/proc-macro-error/src/dummy.rs deleted file mode 100644 index f7443b3..0000000 --- a/proc-macro-error/proc-macro-error/src/dummy.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Facility to emit dummy implementations (or whatever) in case -//! an error happen. -//! -//! `compile_error!` does not abort a compilation right away. This means -//! `rustc` doesn't just show you the error and abort, it carries on the -//! compilation process looking for other errors to report. -//! -//! Let's consider an example: -//! -//! ```rust,ignore -//! use proc_macro::TokenStream; -//! use proc_macro_error::*; -//! -//! trait MyTrait { -//! fn do_thing(); -//! } -//! -//! // this proc macro is supposed to generate MyTrait impl -//! #[proc_macro_derive(MyTrait)] -//! #[proc_macro_error] -//! fn example(input: TokenStream) -> TokenStream { -//! // somewhere deep inside -//! abort!(span, "something's wrong"); -//! -//! // this implementation will be generated if no error happened -//! quote! { -//! impl MyTrait for #name { -//! fn do_thing() {/* whatever */} -//! } -//! } -//! } -//! -//! // ================ -//! // in main.rs -//! -//! // this derive triggers an error -//! #[derive(MyTrait)] // first BOOM! -//! struct Foo; -//! -//! fn main() { -//! Foo::do_thing(); // second BOOM! -//! } -//! ``` -//! -//! The problem is: the generated token stream contains only `compile_error!` -//! invocation, the impl was not generated. That means user will see two compilation -//! errors: -//! -//! ```text -//! error: something's wrong -//! --> $DIR/probe.rs:9:10 -//! | -//! 9 |#[proc_macro_derive(MyTrait)] -//! | ^^^^^^^ -//! -//! error[E0599]: no function or associated item named `do_thing` found for type `Foo` in the current scope -//! --> src\main.rs:3:10 -//! | -//! 1 | struct Foo; -//! | ----------- function or associated item `do_thing` not found for this -//! 2 | fn main() { -//! 3 | Foo::do_thing(); // second BOOM! -//! | ^^^^^^^^ function or associated item not found in `Foo` -//! ``` -//! -//! But the second error is meaningless! We definitely need to fix this. -//! -//! Most used approach in cases like this is "dummy implementation" - -//! omit `impl MyTrait for #name` and fill functions bodies with `unimplemented!()`. -//! -//! This is how you do it: -//! -//! ```rust,ignore -//! use proc_macro::TokenStream; -//! use proc_macro_error::*; -//! -//! trait MyTrait { -//! fn do_thing(); -//! } -//! -//! // this proc macro is supposed to generate MyTrait impl -//! #[proc_macro_derive(MyTrait)] -//! #[proc_macro_error] -//! fn example(input: TokenStream) -> TokenStream { -//! // first of all - we set a dummy impl which will be appended to -//! // `compile_error!` invocations in case a trigger does happen -//! set_dummy(quote! { -//! impl MyTrait for #name { -//! fn do_thing() { unimplemented!() } -//! } -//! }); -//! -//! // somewhere deep inside -//! abort!(span, "something's wrong"); -//! -//! // this implementation will be generated if no error happened -//! quote! { -//! impl MyTrait for #name { -//! fn do_thing() {/* whatever */} -//! } -//! } -//! } -//! -//! // ================ -//! // in main.rs -//! -//! // this derive triggers an error -//! #[derive(MyTrait)] // first BOOM! -//! struct Foo; -//! -//! fn main() { -//! Foo::do_thing(); // no more errors! -//! } -//! ``` - -use proc_macro2::TokenStream; -use std::cell::Cell; - -use crate::check_correctness; - -thread_local! { - static DUMMY_IMPL: Cell<Option<TokenStream>> = Cell::new(None); -} - -/// Sets dummy token stream which will be appended to `compile_error!(msg);...` -/// invocations in case you'll emit any errors. -/// -/// See [guide](../index.html#guide). -pub fn set_dummy(dummy: TokenStream) -> Option<TokenStream> { - check_correctness(); - DUMMY_IMPL.with(|old_dummy| old_dummy.replace(Some(dummy))) -} - -pub(crate) fn cleanup() -> Option<TokenStream> { - DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None)) -} diff --git a/proc-macro-error/proc-macro-error/src/lib.rs b/proc-macro-error/proc-macro-error/src/lib.rs deleted file mode 100644 index 5fb0223..0000000 --- a/proc-macro-error/proc-macro-error/src/lib.rs +++ /dev/null @@ -1,514 +0,0 @@ -//! # proc-macro-error -//! -//! This crate aims to make error reporting in proc-macros simple and easy to use. -//! Migrate from `panic!`-based errors for as little effort as possible! -//! -//! Also, there's ability to [append a dummy token stream](dummy/index.html) to your errors. -//! -//! ## Limitations -//! -//! - Warnings are emitted only on nightly, they're ignored on stable. -//! - "help" suggestions cannot have their own span info on stable, (they inherit parent span). -//! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a -//! technical limitation but intentional design, `panic` is not for error reporting. -//! -//! ## Guide -//! -//! ### Macros -//! -//! First of all - **all the emitting-related API must be used within a function -//! annotated with [`#[proc_macro_error]`](#proc_macro_error-attribute) attribute**. You'll just get a -//! panic otherwise, no errors will be shown. -//! -//! For most of the time you will be using macros. -//! -//! - [`abort!`]: -//! -//! Very much panic-like usage - abort execution and show the error. Expands to [`!`] (never type). -//! -//! - [`abort_call_site!`]: -//! -//! Shortcut for `abort!(Span::call_site(), ...)`. Expands to [`!`] (never type). -//! -//! - [`emit_error!`]: -//! -//! [`proc_macro::Diagnostic`]-like usage - emit the error but do not abort the macro. -//! The compilation will fail nonetheless. Expands to [`()`] (unit type). -//! -//! - [`emit_call_site_error!`]: -//! -//! Shortcut for `emit_error!(Span::call_site(), ...)`. Expands to [`()`] (unit type). -//! -//! - [`emit_warning!`]: -//! -//! Like `emit_error!` but emit a warning instead of error. The compilation won't fail -//! because of warnings. -//! Expands to [`()`] (unit type). -//! -//! **Beware**: warnings are nightly only, they are completely ignored on stable. -//! -//! - [`emit_call_site_warning!`]: -//! -//! Shortcut for `emit_warning!(Span::call_site(), ...)`. Expands to `()` (unit type). -//! -//! - [`diagnostic`]: -//! -//! Build instance of `Diagnostic` in format-like style. -//! -//! ### Syntax -//! -//! All the macros have pretty much the same syntax: -//! -//! 1. ```ignore -//! abort!(single_expr) -//! ``` -//! Shortcut for `Diagnostic::from().abort()` -//! -//! 2. ```ignore -//! abort!(span, message) -//! ``` -//! Shortcut for `Diagnostic::spanned(span, message.to_string()).abort()` -//! -//! 3. ```ignore -//! abort!(span, format_literal, format_args...) -//! ``` -//! Shortcut for `Diagnostic::spanned(span, format!(format_literal, format_args...)).abort()` -//! -//! That's it. `abort!`, `emit_warning`, `emit_error` share this exact syntax. -//! `abort_call_site!`, `emit_call_site_warning`, `emit_call_site_error` lack 1 form -//! and do not take span in 2 and 3 forms. -//! -//! `diagnostic!` require `Level` instance between `span` and second argument (1 form is the same). -//! -//! #### Note attachments -//! -//! 3. Every macro can have "note" attachments (only 2 and 3 form). -//! ```ignore -//! let opt_help = if have_some_info { Some("did you mean `this`?") } else { None }; -//! -//! abort!( -//! span, message; // <--- attachments start with `;` (semicolon) -//! -//! help = "format {} {}", "arg1", "arg2"; // <--- every attachment ends with `;`, -//! // maybe except the last one -//! -//! note = "to_string"; // <--- one arg uses `.to_string()` instead of `format!()` -//! -//! yay = "I see what {} did here", "you"; // <--- "help =" and "hint =" are mapped to Diagnostic::help -//! // anything else is Diagnostic::note -//! -//! wow = note_span => "custom span"; // <--- attachments can have their own span -//! // it takes effect only on nightly though -//! -//! hint =? opt_help; // <-- "optional" attachment, get displayed only if `Some` -//! // must be single `Option` expression -//! -//! note =? note_span => opt_help // <-- optional attachments can have custom spans too -//! ) -//! ``` -//! -//! ### `#[proc_macro_error]` attribute -//! -//! **This attribute MUST be present on the top level of your macro.** -//! -//! This attribute performs the setup and cleanup necessary to make things work. -//! -//! #### Syntax -//! -//! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...` -//! is a comma-separated list of: -//! -//! - `proc_macro_hack`: -//! -//! To correctly cooperate with `#[proc_macro_hack]` `#[proc_macro_error]` -//! attribute must be placed *before* (above) it, like this: -//! -//! ```ignore -//! #[proc_macro_error] -//! #[proc_macro_hack] -//! #[proc_macro] -//! fn my_macro(input: TokenStream) -> TokenStream { -//! unimplemented!() -//! } -//! ``` -//! -//! If, for some reason, you can't place it like that you can use -//! `#[proc_macro_error(proc_macro_hack)]` instead. -//! -//! - `allow_not_macro`: -//! -//! By default, the attribute checks that it's applied to a proc-macro. -//! If none of `#[proc_macro]`, `#[proc_macro_derive]` nor `#[proc_macro_attribute]` are -//! present it will panic. It's the intention - this crate is supposed to be used only with -//! proc-macros. This setting is made to bypass the check, useful in certain -//! circumstances. -//! -//! Please note: the function this attribute is applied to must return `proc_macro::TokenStream`. -//! -//! - `assert_unwind_safe`: -//! -//! By default, your code must be [unwind safe]. If your code is not unwind safe but you believe -//! it's correct you can use this setting to bypass the check. This is typically needed -//! for code that uses `lazy_static` or `thread_local` with `Cell/RefCell` inside. -//! -//! This setting is implied if `#[proc_macro_error]` is applied to a function -//! marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`. -//! -//! ### Diagnostic type -//! -//! [`Diagnostic`] type is intentionally designed to be API compatible with [`proc_macro::Diagnostic`]. -//! Not all API is implemented, only the part that can be reasonably implemented on stable. -//! -//! -//! [`abort!`]: macro.abort.html -//! [`emit_warning!`]: macro.emit_warning.html -//! [`emit_error!`]: macro.emit_error.html -//! [`abort_call_site!`]: macro.abort_call_site.html -//! [`emit_call_site_warning!`]: macro.emit_call_site_error.html -//! [`emit_call_site_error!`]: macro.emit_call_site_warning.html -//! [`diagnostic!`]: macro.diagnostic.html -//! [proc_macro_error]: ./../proc_macro_error_attr/attr.proc_macro_error.html -//! [`Diagnostic`]: struct.Diagnostic.html -//! [`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html -//! [unwind safe]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html#what-is-unwind-safety -//! [`!`]: https://doc.rust-lang.org/std/primitive.never.html -//! [`()`]: https://doc.rust-lang.org/std/primitive.unit.html - -#![cfg_attr(pme_nightly, feature(proc_macro_diagnostic))] -#![forbid(unsafe_code)] - -// reexports for use in macros -#[doc(hidden)] -pub extern crate proc_macro; -#[doc(hidden)] -pub extern crate proc_macro2; - -pub use self::dummy::set_dummy; -pub use proc_macro_error_attr::proc_macro_error; - -use proc_macro2::{Span, TokenStream}; -use quote::quote; -use quote::{quote_spanned, ToTokens}; -use std::cell::Cell; -use std::panic::{catch_unwind, resume_unwind, UnwindSafe}; - -pub mod dummy; - -mod macros; - -#[cfg(not(any(pme_nightly, nightly_fmt)))] -#[path = "stable.rs"] -mod imp; - -#[cfg(any(pme_nightly, nightly_fmt))] -#[path = "nightly.rs"] -mod imp; - -/// Represents a diagnostic level -/// -/// # Warnings -/// -/// Warnings are ignored on stable/beta -#[derive(Debug, PartialEq)] -pub enum Level { - Error, - Warning, - #[doc(hidden)] - NonExhaustive, -} - -/// Represents a single diagnostic message -#[derive(Debug)] -pub struct Diagnostic { - level: Level, - span: Span, - msg: String, - suggestions: Vec<(SuggestionKind, String, Option<Span>)>, -} - -/// This traits expands `Result<T, Into<Diagnostic>>` with some handy shortcuts. -pub trait ResultExt { - type Ok; - - /// Behaves like `Result::unwrap`: if self is `Ok` yield the contained value, - /// otherwise abort macro execution via `abort!`. - fn unwrap_or_abort(self) -> Self::Ok; - - /// Behaves like `Result::expect`: if self is `Ok` yield the contained value, - /// otherwise abort macro execution via `abort!`. - /// If it aborts then resulting error message will be preceded with `message`. - fn expect_or_abort(self, msg: &str) -> Self::Ok; -} - -/// This traits expands `Option` with some handy shortcuts. -pub trait OptionExt { - type Some; - - /// Behaves like `Option::expect`: if self is `Some` yield the contained value, - /// otherwise abort macro execution via `abort_call_site!`. - /// If it aborts the `message` will be used for [`compile_error!`][compl_err] invocation. - /// - /// [compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html - fn expect_or_abort(self, msg: &str) -> Self::Some; -} - -impl Diagnostic { - /// Create a new diagnostic message that points to `Span::call_site()` - pub fn new(level: Level, message: String) -> Self { - Diagnostic::spanned(Span::call_site(), level, message) - } - - /// Create a new diagnostic message that points to the `span` - pub fn spanned(span: Span, level: Level, message: String) -> Self { - Diagnostic { - level, - span, - msg: message, - suggestions: vec![], - } - } - - /// Attach a "help" note to your main message, note will have it's own span on nightly. - /// - /// # Span - /// - /// The span is ignored on stable, the note effectively inherits its parent's (main message) span - pub fn span_help(mut self, span: Span, msg: String) -> Self { - self.suggestions - .push((SuggestionKind::Help, msg, Some(span))); - self - } - - /// Attach a "help" note to your main message, - pub fn help(mut self, msg: String) -> Self { - self.suggestions.push((SuggestionKind::Help, msg, None)); - self - } - - /// Attach a note to your main message, note will have it's own span on nightly. - /// - /// # Span - /// - /// The span is ignored on stable, the note effectively inherits its parent's (main message) span - pub fn span_note(mut self, span: Span, msg: String) -> Self { - self.suggestions - .push((SuggestionKind::Note, msg, Some(span))); - self - } - - /// Attach a note to your main message - pub fn note(mut self, msg: String) -> Self { - self.suggestions.push((SuggestionKind::Note, msg, None)); - self - } - - /// The message of main warning/error (no notes attached) - pub fn message(&self) -> &str { - &self.msg - } - - /// Abort the proc-macro's execution and display the diagnostic. - /// - /// # Warnings - /// - /// Warnings do not get emitted on stable/beta but this function will abort anyway. - pub fn abort(self) -> ! { - self.emit(); - abort_now() - } - - /// Display the diagnostic while not aborting macro execution. - /// - /// # Warnings - /// - /// Warnings are ignored on stable/beta - pub fn emit(self) { - imp::emit_diagnostic(self); - } -} - -/// Abort macro execution and display all the emitted errors, if any. -/// -/// Does nothing if no errors were emitted (warnings do not count). -pub fn abort_if_dirty() { - imp::abort_if_dirty(); -} - -#[doc(hidden)] -impl Diagnostic { - pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self { - match suggestion { - "help" | "hint" => self.span_help(span, msg), - _ => self.span_note(span, msg), - } - } - - pub fn suggestion(self, suggestion: &str, msg: String) -> Self { - match suggestion { - "help" | "hint" => self.help(msg), - _ => self.note(msg), - } - } -} - -impl ToTokens for Diagnostic { - fn to_tokens(&self, ts: &mut TokenStream) { - use std::borrow::Cow; - - fn ensure_lf(buf: &mut String, s: &str) { - if s.ends_with('\n') { - buf.push_str(s); - } else { - buf.push_str(s); - buf.push('\n'); - } - } - - let Diagnostic { - ref msg, - ref suggestions, - ref level, - .. - } = *self; - - if *level == Level::Warning { - return; - } - - let message = if suggestions.is_empty() { - Cow::Borrowed(msg) - } else { - let mut message = String::new(); - ensure_lf(&mut message, msg); - message.push('\n'); - - for (kind, note, _span) in suggestions { - message.push_str(" = "); - message.push_str(kind.name()); - message.push_str(": "); - ensure_lf(&mut message, note); - } - message.push('\n'); - - Cow::Owned(message) - }; - - let span = &self.span; - let msg = syn::LitStr::new(&*message, *span); - ts.extend(quote_spanned!(*span=> compile_error!(#msg); )); - } -} - -impl<T, E: Into<Diagnostic>> ResultExt for Result<T, E> { - type Ok = T; - - fn unwrap_or_abort(self) -> T { - match self { - Ok(res) => res, - Err(e) => e.into().abort(), - } - } - - fn expect_or_abort(self, message: &str) -> T { - match self { - Ok(res) => res, - Err(e) => { - let mut e = e.into(); - e.msg = format!("{}: {}", message, e.msg); - e.abort() - } - } - } -} - -impl<T> OptionExt for Option<T> { - type Some = T; - - fn expect_or_abort(self, message: &str) -> T { - match self { - Some(res) => res, - None => abort_call_site!(message), - } - } -} - -#[derive(Debug)] -enum SuggestionKind { - Help, - Note, -} - -impl SuggestionKind { - fn name(&self) -> &'static str { - match self { - SuggestionKind::Note => "note", - SuggestionKind::Help => "help", - } - } -} - -impl From<syn::Error> for Diagnostic { - fn from(e: syn::Error) -> Self { - Diagnostic::spanned(e.span(), Level::Error, e.to_string()) - } -} - -/// This is the entry point for a proc-macro. -/// -/// **NOT PUBLIC API, SUBJECT TO CHANGE WITHOUT ANY NOTICE** -#[doc(hidden)] -pub fn entry_point<F>(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream -where - F: FnOnce() -> proc_macro::TokenStream + UnwindSafe, -{ - ENTERED_ENTRY_POINT.with(|flag| flag.set(true)); - let caught = catch_unwind(f); - let dummy = dummy::cleanup(); - let err_storage = imp::cleanup(); - ENTERED_ENTRY_POINT.with(|flag| flag.set(false)); - - let mut appendix = TokenStream::new(); - if proc_macro_hack { - appendix.extend(quote! { - #[allow(unused)] - macro_rules! proc_macro_call { - () => ( unimplemented!() ) - } - }); - } - - match caught { - Ok(ts) => { - if err_storage.is_empty() { - ts - } else { - quote!( #(#err_storage)* #dummy #appendix ).into() - } - } - - Err(boxed) => match boxed.downcast::<AbortNow>() { - Ok(_) => quote!( #(#err_storage)* #dummy #appendix ).into(), - Err(boxed) => resume_unwind(boxed), - }, - } -} - -fn abort_now() -> ! { - check_correctness(); - panic!(AbortNow) -} - -thread_local! { - static ENTERED_ENTRY_POINT: Cell<bool> = Cell::new(false); -} - -struct AbortNow; - -fn check_correctness() { - if !ENTERED_ENTRY_POINT.with(|flag| flag.get()) { - panic!( - "proc-macro-error API cannot be used outside of `entry_point` invocation, \ - perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]" - ); - } -} diff --git a/proc-macro-error/proc-macro-error/src/macros.rs b/proc-macro-error/proc-macro-error/src/macros.rs deleted file mode 100644 index 117612c..0000000 --- a/proc-macro-error/proc-macro-error/src/macros.rs +++ /dev/null @@ -1,257 +0,0 @@ -// FIXME: this can be greatly simplified via $()? -// as soon as MRSV hits 1.32 - -/// Build [`Diagnostic`](struct.Diagnostic.html) instance from provided arguments. -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -/// -#[macro_export] -macro_rules! diagnostic { - // from alias - ($err:expr) => { $crate::Diagnostic::from($err) }; - - // span, message, help - ($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{ - let diag = $crate::Diagnostic::spanned( - $span.into(), - $level, - format!($fmt, $($args),*) - ); - $crate::__pme__suggestions!(diag $($rest)*); - diag - }}; - - ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{ - let diag = $crate::Diagnostic::spanned($span.into(), $level, $msg.to_string()); - $crate::__pme__suggestions!(diag $($rest)*); - diag - }}; - - // span, message, no help - ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{ - $crate::Diagnostic::spanned( - $span.into(), - $level, - format!($fmt, $($args),*) - ) - }}; - - ($span:expr, $level:expr, $msg:expr) => {{ - $crate::Diagnostic::spanned($span.into(), $level, $msg.to_string()) - }}; - - - // trailing commas - - ($span:expr, $level:expr, $fmt:expr, $($args:expr),+, ; $($rest:tt)+) => { - $crate::diagnostic!($span, $level, $fmt, $($args),* ; $($rest)*) - }; - ($span:expr, $level:expr, $msg:expr, ; $($rest:tt)+) => { - $crate::diagnostic!($span, $level, $msg ; $($rest)*) - }; - ($span:expr, $level:expr, $fmt:expr, $($args:expr),+,) => { - $crate::diagnostic!($span, $level, $fmt, $($args),*) - }; - ($span:expr, $level:expr, $msg:expr,) => { - $crate::diagnostic!($span, $level, $msg) - }; - // ($err:expr,) => { $crate::diagnostic!($err) }; -} - -/// Abort proc-macro execution right now and display the error. -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -#[macro_export] -macro_rules! abort { - ($err:expr) => { - $crate::diagnostic!($err).abort() - }; - - ($span:expr, $($tts:tt)*) => { - $crate::diagnostic!($span, $crate::Level::Error, $($tts)*).abort() - }; -} - -/// Shortcut for `abort!(Span::call_site(), msg...)`. This macro -/// is still preferable over plain panic, panics are not for error reporting. -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -/// -#[macro_export] -macro_rules! abort_call_site { - ($($tts:tt)*) => { - $crate::diagnostic!( - $crate::proc_macro2::Span::call_site(), - $crate::Level::Error, - $($tts)* - ).abort() - }; -} - -/// Emit an error while not aborting the proc-macro right away. -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -/// -#[macro_export] -macro_rules! emit_error { - ($err:expr) => { - $crate::diagnostic!($err).emit() - }; - - ($span:expr, $($tts:tt)*) => {{ - let level = $crate::Level::Error; - $crate::diagnostic!($span, level, $($tts)*).emit() - }}; -} - -/// Shortcut for `emit_error!(Span::call_site(), ...)`. This macro -/// is still preferable over plain panic, panics are not for error reporting.. -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -/// -#[macro_export] -macro_rules! emit_call_site_error { - ($($tts:tt)*) => { - $crate::diagnostic!( - $crate::proc_macro2::Span()::call_site(), - $crate::Level::Error, - $($tts)* - ).emit() - }; -} - -/// Emit a warning. Warnings are not errors and compilation won't fail because of them. -/// -/// **Does nothing on stable** -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -/// -#[macro_export] -macro_rules! emit_warning { - ($span:expr, $($tts:tt)*) => { - $crate::diagnostic!($span, $crate::Level::Warning, $($tts)*).emit() - }; -} - -/// Shortcut for `emit_warning!(Span::call_site(), ...)`. -/// -/// **Does nothing on stable** -/// -/// # Syntax -/// -/// See [the guide](index.html#guide). -/// -#[macro_export] -macro_rules! emit_call_site_warning { - ($($tts:tt)*) => {{ - let span = $crate::proc_macro2::Span()::call_site(); - $crate::diagnostic!(span, $crate::Level::Warning, $($tts)*).emit() - }}; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! __pme__suggestions { - ($var:ident) => (); - - ($var:ident $help:ident =? $msg:expr) => { - let $var = if let Some(msg) = $msg { - $var.suggestion(stringify!($help), msg.to_string()) - } else { - $var - }; - }; - ($var:ident $help:ident =? $span:expr => $msg:expr) => { - let $var = if let Some(msg) = $msg { - $var.span_suggestion($span.into(), stringify!($help), msg.to_string()) - } else { - $var - }; - }; - - ($var:ident $help:ident =? $msg:expr ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help =? $msg); - $crate::__pme__suggestions!($var $($rest)*); - }; - ($var:ident $help:ident =? $span:expr => $msg:expr ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help =? $span => $msg); - $crate::__pme__suggestions!($var $($rest)*); - }; - - - ($var:ident $help:ident = $msg:expr) => { - let $var = $var.suggestion(stringify!($help), $msg.to_string()); - }; - ($var:ident $help:ident = $fmt:expr, $($args:expr),+) => { - let $var = $var.suggestion( - stringify!($help), - format!($fmt, $($args),*) - ); - }; - ($var:ident $help:ident = $span:expr => $msg:expr) => { - let $var = $var.span_suggestion($span.into(), stringify!($help), $msg.to_string()); - }; - ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+) => { - let $var = $var.span_suggestion( - $span.into(), - stringify!($help), - format!($fmt, $($args),*) - ); - }; - - ($var:ident $help:ident = $msg:expr ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $msg); - $crate::__pme__suggestions!($var $($rest)*); - }; - ($var:ident $help:ident = $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $fmt, $($args),*); - $crate::__pme__suggestions!($var $($rest)*); - }; - ($var:ident $help:ident = $span:expr => $msg:expr ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $span => $msg); - $crate::__pme__suggestions!($var $($rest)*); - }; - ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*); - $crate::__pme__suggestions!($var $($rest)*); - }; - - // trailing commas - - ($var:ident $help:ident = $msg:expr,) => { - $crate::__pme__suggestions!($var $help = $msg) - }; - ($var:ident $help:ident = $fmt:expr, $($args:expr),+,) => { - $crate::__pme__suggestions!($var $help = $fmt, $($args)*) - }; - ($var:ident $help:ident = $span:expr => $msg:expr,) => { - $crate::__pme__suggestions!($var $help = $span => $msg) - }; - ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),*,) => { - $crate::__pme__suggestions!($var $help = $span => $fmt, $($args)*) - }; - ($var:ident $help:ident = $msg:expr, ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $msg; $($rest)*) - }; - ($var:ident $help:ident = $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $fmt, $($args),*; $($rest)*) - }; - ($var:ident $help:ident = $span:expr => $msg:expr, ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $span => $msg; $($rest)*) - }; - ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => { - $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*; $($rest)*) - }; -} diff --git a/proc-macro-error/proc-macro-error/src/nightly.rs b/proc-macro-error/proc-macro-error/src/nightly.rs deleted file mode 100644 index d053c2f..0000000 --- a/proc-macro-error/proc-macro-error/src/nightly.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering}; - -use proc_macro::{Diagnostic as PDiag, Level as PLevel}; - -use crate::{abort_now, check_correctness, Diagnostic, Level, SuggestionKind}; - -pub fn abort_if_dirty() { - check_correctness(); - if IS_DIRTY.load(Ordering::SeqCst) { - abort_now() - } -} - -pub(crate) fn cleanup() -> Vec<Diagnostic> { - vec![] -} - -pub(crate) fn emit_diagnostic(diag: Diagnostic) { - let Diagnostic { - level, - span, - msg, - suggestions, - } = diag; - - let level = match level { - Level::Warning => PLevel::Warning, - Level::Error => { - IS_DIRTY.store(true, Ordering::SeqCst); - PLevel::Error - } - _ => unreachable!(), - }; - - let mut res = PDiag::spanned(span.unwrap(), level, msg); - - for (kind, msg, span) in suggestions { - res = match (kind, span) { - (SuggestionKind::Note, Some(span)) => res.span_note(span.unwrap(), msg), - (SuggestionKind::Help, Some(span)) => res.span_help(span.unwrap(), msg), - (SuggestionKind::Note, None) => res.note(msg), - (SuggestionKind::Help, None) => res.help(msg), - } - } - - res.emit() -} - -static IS_DIRTY: AtomicBool = AtomicBool::new(false); diff --git a/proc-macro-error/proc-macro-error/src/stable.rs b/proc-macro-error/proc-macro-error/src/stable.rs deleted file mode 100644 index 07042d3..0000000 --- a/proc-macro-error/proc-macro-error/src/stable.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::cell::RefCell; - -use crate::{abort_now, check_correctness, Diagnostic, Level}; - -pub fn abort_if_dirty() { - check_correctness(); - ERR_STORAGE.with(|storage| { - if !storage.borrow().is_empty() { - abort_now() - } - }); -} - -pub(crate) fn cleanup() -> Vec<Diagnostic> { - ERR_STORAGE.with(|storage| storage.replace(Vec::new())) -} - -pub(crate) fn emit_diagnostic(diag: Diagnostic) { - if diag.level == Level::Error { - ERR_STORAGE.with(|storage| storage.borrow_mut().push(diag)); - } -} - -thread_local! { - static ERR_STORAGE: RefCell<Vec<Diagnostic>> = RefCell::new(Vec::new()); -} |