Import proc-macro-error-1.0.2

Change-Id: Iebb634ed3b9e204e58ffc8c1035d9e982748ea62
diff --git a/src/diagnostic.rs b/src/diagnostic.rs
new file mode 100644
index 0000000..5ec8ce2
--- /dev/null
+++ b/src/diagnostic.rs
@@ -0,0 +1,277 @@
+use crate::{abort_now, check_correctness};
+use proc_macro2::Span;
+use proc_macro2::TokenStream;
+
+use quote::{quote_spanned, ToTokens};
+
+/// 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 {
+    pub(crate) level: Level,
+    pub(crate) start: Span,
+    pub(crate) end: Span,
+    pub(crate) msg: String,
+    pub(crate) suggestions: Vec<(SuggestionKind, String, Option<Span>)>,
+    pub(crate) children: Vec<(Span, Span, String)>,
+}
+
+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::double_spanned(span, span, level, message)
+    }
+
+    /// Add another error message to self such that it will be emitted right after
+    /// the main message.
+    pub fn span_error(self, span: Span, msg: String) -> Self {
+        self.double_span_error(span, span, msg)
+    }
+
+    /// Attach a "help" note to your main message, the 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, the 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) {
+        check_correctness();
+        crate::imp::emit_diagnostic(self);
+    }
+}
+
+/// **NOT PUBLIC API! NOTHING TO SEE HERE!!!**
+#[doc(hidden)]
+impl Diagnostic {
+    pub fn double_spanned(start: Span, end: Span, level: Level, message: String) -> Self {
+        Diagnostic {
+            level,
+            start,
+            end,
+            msg: message,
+            suggestions: vec![],
+            children: vec![],
+        }
+    }
+
+    pub fn double_span_error(mut self, start: Span, end: Span, msg: String) -> Self {
+        self.children.push((start, end, msg));
+        self
+    }
+
+    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');
+            }
+        }
+
+        fn diag_to_tokens(
+            start: Span,
+            end: Span,
+            level: &Level,
+            msg: &str,
+            suggestions: &[(SuggestionKind, String, Option<Span>)],
+        ) -> TokenStream {
+            if *level == Level::Warning {
+                return TokenStream::new();
+            }
+
+            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 msg = syn::LitStr::new(&*message, end);
+            let group = quote_spanned!(end=> { #msg } );
+            quote_spanned!(start=> compile_error!#group)
+        }
+
+        ts.extend(diag_to_tokens(
+            self.start,
+            self.end,
+            &self.level,
+            &self.msg,
+            &self.suggestions,
+        ));
+        ts.extend(
+            self.children
+                .iter()
+                .map(|(start, end, msg)| diag_to_tokens(*start, *end, &Level::Error, &msg, &[])),
+        );
+    }
+}
+
+#[derive(Debug)]
+pub(crate) 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(err: syn::Error) -> Self {
+        use proc_macro2::{Delimiter, TokenTree};
+
+        fn gut_error(ts: &mut impl Iterator<Item = TokenTree>) -> Option<(Span, Span, String)> {
+            let start = match ts.next() {
+                // compile_error
+                None => return None,
+                Some(tt) => tt.span(),
+            };
+            ts.next().unwrap(); // !
+
+            let lit = match ts.next().unwrap() {
+                TokenTree::Group(group) => {
+                    // Currently `syn` builds `compile_error!` invocations
+                    // exclusively in `ident{"..."}` (braced) form which is not
+                    // followed by `;` (semicolon).
+                    //
+                    // But if it changes to `ident("...");` (parenthesized)
+                    // or `ident["..."];` (bracketed) form,
+                    // we will need to skip the `;` as well.
+                    // Highly unlikely, but better safe than sorry.
+
+                    if group.delimiter() == Delimiter::Parenthesis
+                        || group.delimiter() == Delimiter::Bracket
+                    {
+                        ts.next().unwrap(); // ;
+                    }
+
+                    match group.stream().into_iter().next().unwrap() {
+                        TokenTree::Literal(lit) => lit,
+                        _ => unreachable!(),
+                    }
+                }
+                _ => unreachable!(),
+            };
+
+            let end = lit.span();
+            let mut msg = lit.to_string();
+
+            // "abc" => abc
+            msg.pop();
+            msg.remove(0);
+
+            Some((start, end, msg))
+        }
+
+        let mut ts = err.to_compile_error().into_iter();
+
+        let (start, end, msg) = gut_error(&mut ts).unwrap();
+        let mut res = Diagnostic::double_spanned(start, end, Level::Error, msg);
+
+        while let Some((start, end, msg)) = gut_error(&mut ts) {
+            res = res.double_span_error(start, end, msg);
+        }
+
+        res
+    }
+}
diff --git a/src/dummy.rs b/src/dummy.rs
new file mode 100644
index 0000000..571a595
--- /dev/null
+++ b/src/dummy.rs
@@ -0,0 +1,150 @@
+//! 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::RefCell;
+
+use crate::check_correctness;
+
+thread_local! {
+    static DUMMY_IMPL: RefCell<Option<TokenStream>> = RefCell::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)))
+}
+
+/// Same as [`set_dummy`] but, instead of resetting, appends tokens to the
+/// existing dummy (if any). Behaves as `set_dummy` if no dummy is present.
+pub fn append_dummy(dummy: TokenStream) {
+    check_correctness();
+    DUMMY_IMPL.with(|old_dummy| {
+        let mut cell = old_dummy.borrow_mut();
+        if let Some(ts) = cell.as_mut() {
+            ts.extend(dummy);
+        } else {
+            *cell = Some(dummy);
+        }
+    });
+}
+
+pub(crate) fn cleanup() -> Option<TokenStream> {
+    DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None))
+}
diff --git a/src/imp/delegate.rs b/src/imp/delegate.rs
new file mode 100644
index 0000000..c096803
--- /dev/null
+++ b/src/imp/delegate.rs
@@ -0,0 +1,66 @@
+//! This implementation uses [`proc_macro::Diagnostic`], nightly only.
+
+use std::cell::Cell;
+
+use proc_macro::{Diagnostic as PDiag, Level as PLevel};
+
+use crate::{
+    abort_now, check_correctness,
+    diagnostic::{Diagnostic, Level, SuggestionKind},
+};
+
+pub fn abort_if_dirty() {
+    check_correctness();
+    if IS_DIRTY.with(|c| c.get()) {
+        abort_now()
+    }
+}
+
+pub(crate) fn cleanup() -> Vec<Diagnostic> {
+    IS_DIRTY.with(|c| c.set(false));
+    vec![]
+}
+
+pub(crate) fn emit_diagnostic(diag: Diagnostic) {
+    let Diagnostic {
+        level,
+        start,
+        end,
+        msg,
+        suggestions,
+        children,
+    } = diag;
+
+    let span = start.join(end).unwrap_or(start);
+
+    let level = match level {
+        Level::Warning => PLevel::Warning,
+        Level::Error => {
+            IS_DIRTY.with(|c| c.set(true));
+            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),
+        }
+    }
+
+    for (start, end, msg) in children {
+        let span = start.join(end).unwrap_or(start).unwrap();
+        res = res.span_error(span, msg);
+    }
+
+    res.emit()
+}
+
+thread_local! {
+    static IS_DIRTY: Cell<bool> = Cell::new(false);
+}
diff --git a/src/imp/fallback.rs b/src/imp/fallback.rs
new file mode 100644
index 0000000..ad1f730
--- /dev/null
+++ b/src/imp/fallback.rs
@@ -0,0 +1,30 @@
+//! This implementation uses self-written stable facilities.
+
+use crate::{
+    abort_now, check_correctness,
+    diagnostic::{Diagnostic, Level},
+};
+use std::cell::RefCell;
+
+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());
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..0af2de3
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,466 @@
+//! # 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.
+//!
+//! ## Real world examples
+//!
+//! * [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive)
+//!   (abort-like usage)
+//! * [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage)
+//!
+//! ## Limitations
+//!
+//! - Warnings are emitted only on nightly, they are ignored on stable.
+//! - "help" suggestions can't have their own span info on stable,
+//!   (essentially inheriting the parent span).
+//! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a
+//!   technical limitation but rather intentional design. `panic` is not for error reporting.
+//!
+//! ### `#[proc_macro_error]` attribute
+//!
+//! **This attribute MUST be present on the top level of your macro** (the function
+//! annotated with any of `#[proc_macro]`, `#[proc_macro_derive]`, `#[proc_macro_attribute]`).
+//!
+//! This attribute performs the setup and cleanup necessary to make things work.
+//!
+//! In most cases you'll need the simple `#[proc_macro_error]` form without any
+//! additional settings. Feel free to [skip the "Syntax" section](#macros).
+//!
+//! #### Syntax
+//!
+//! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...`
+//! is a comma-separated list of:
+//!
+//! - `proc_macro_hack`:
+//!
+//!     In order to correctly cooperate with `#[proc_macro_hack]`, `#[proc_macro_error]`
+//!     attribute must be placed *before* (above) it, like this:
+//!
+//!     ```no_run
+//!     # use proc_macro2::TokenStream;
+//!     # const IGNORE: &str = "
+//!     #[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.
+//!
+//!     # Note
+//!
+//!     If `proc-macro-hack` was detected (by any means) `allow_not_macro`
+//!     and `assert_unwind_safe` will be applied automatically.
+//!
+//! - `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.
+//!
+//!     Pay attention: the function this attribute is applied to must return
+//!     `proc_macro::TokenStream`.
+//!
+//!     This setting is implied if `proc-macro-hack` was detected.
+//!
+//! - `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.
+//!     You would need this for code that uses `lazy_static` or `thread_local` with
+//!     `Cell/RefCell` inside (and the like).
+//!
+//!     This setting is implied if `#[proc_macro_error]` is applied to a function
+//!     marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`.
+//!
+//!     This setting is also implied if `proc-macro-hack` was detected.
+//!
+//! ## Macros
+//!
+//! Most of the time you want to use the macros. Syntax is described in the next section below.
+//!
+//! You'll need to decide how you want to emit errors:
+//!
+//! * Emit the error and abort. Very much panic-like usage. Served by [`abort!`] and
+//!   [`abort_call_site!`].
+//! * Emit the error but do not abort right away, looking for other errors to report.
+//!   Served by [`emit_error!`] and [`emit_call_site_error!`].
+//!
+//! You **can** mix these usages.
+//!
+//! `abort` and `emit_error` take a "source span" as the first argument. This source
+//! will be used to highlight the place the error originates from. It must be one of:
+//!
+//! * *Something* that implements [`ToTokens`] (most types in `syn` and `proc-macro2` do).
+//!   This source is the preferable one since it doesn't lose span information on multi-token
+//!   spans, see [this issue](https://gitlab.com/CreepySkeleton/proc-macro-error/-/issues/6)
+//!   for details.
+//! * [`proc_macro::Span`]
+//! * [`proc-macro2::Span`]
+//!
+//! The rest is your message in format-like style.
+//!
+//! See [the next section](#syntax-1) for detailed syntax.
+//!
+//! - [`abort!`]:
+//!
+//!     Very much panic-like usage - abort right away 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 keep going,
+//!     looking for other errors to report.
+//!     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 an 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(expr).abort()`.
+//!
+//! 2.  ```ignore
+//!     abort!(span, message)
+//!     ```
+//!     The first argument is an expression the span info should be taken from.
+//!
+//!     The second argument is the error message, it must implement [`ToString`].
+//!
+//! 3.  ```ignore
+//!     abort!(span, format_literal, format_args...)
+//!     ```
+//!
+//!     This form is pretty much the same as 2, except `format!(format_literal, format_args...)`
+//!     will be used to for the message instead of [`ToString`].
+//!
+//! 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'th and 3'th forms. Those are essentially shortcuts for
+//! `macro!(Span::call_site(), args...)`.
+//!
+//! `diagnostic!` requires a [`Level`] instance between `span` and second argument
+//! (1'th form is the same).
+//!
+//! > **Important!**
+//! >
+//! > If you have some type from `proc_macro` or `syn` to point to, do not call `.span()`
+//! > on it but rather use it directly:
+//! > ```no_run
+//! > # use proc_macro_error::abort;
+//! > # let input = proc_macro2::TokenStream::new();
+//! > let ty: syn::Type = syn::parse2(input).unwrap();
+//! > abort!(ty, "BOOM");
+//! > //     ^^ <-- avoid .span()
+//! > ```
+//! >
+//! > `.span()` calls work too, but you may experience regressions in message quality.
+//!
+//! #### 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
+//!   );
+//!   ```
+//!
+
+//! ### 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
+//! [`abort_call_site!`]: macro.abort_call_site.html
+//! [`emit_warning!`]: macro.emit_warning.html
+//! [`emit_error!`]: macro.emit_error.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
+//! [`Diagnostic`]: struct.Diagnostic.html
+//!
+//! [`proc_macro::Span`]: https://doc.rust-lang.org/proc_macro/struct.Span.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
+//! [`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html
+//!
+//! [`proc-macro2::Span`]: https://docs.rs/proc-macro2/1.0.10/proc_macro2/struct.Span.html
+//! [`ToTokens`]: https://docs.rs/quote/1.0.3/quote/trait.ToTokens.html
+//!
+
+#![cfg_attr(not(use_fallback), feature(proc_macro_diagnostic))]
+#![forbid(unsafe_code)]
+#![allow(clippy::needless_doctest_main)]
+
+// reexports for use in macros
+#[doc(hidden)]
+pub extern crate proc_macro;
+#[doc(hidden)]
+pub extern crate proc_macro2;
+
+pub use crate::{
+    diagnostic::{Diagnostic, Level},
+    dummy::{append_dummy, set_dummy},
+};
+pub use proc_macro_error_attr::proc_macro_error;
+
+use quote::quote;
+
+use std::cell::Cell;
+use std::panic::{catch_unwind, resume_unwind, UnwindSafe};
+
+pub mod dummy;
+
+mod diagnostic;
+mod macros;
+
+#[cfg(use_fallback)]
+#[path = "imp/fallback.rs"]
+mod imp;
+
+#[cfg(not(use_fallback))]
+#[path = "imp/delegate.rs"]
+mod imp;
+
+/// 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;
+}
+
+/// 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();
+}
+
+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),
+        }
+    }
+}
+
+/// 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(flag.get() + 1));
+    let caught = catch_unwind(f);
+    let dummy = dummy::cleanup();
+    let err_storage = imp::cleanup();
+    ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1));
+
+    let gen_error = || {
+        if proc_macro_hack {
+            quote! {{
+                macro_rules! proc_macro_call {
+                    () => ( unimplemented!() )
+                }
+
+                #(#err_storage)*
+                #dummy
+
+                unimplemented!()
+            }}
+        } else {
+            quote!( #(#err_storage)* #dummy )
+        }
+    };
+
+    match caught {
+        Ok(ts) => {
+            if err_storage.is_empty() {
+                ts
+            } else {
+                gen_error().into()
+            }
+        }
+
+        Err(boxed) => match boxed.downcast::<AbortNow>() {
+            Ok(_) => gen_error().into(),
+            Err(boxed) => resume_unwind(boxed),
+        },
+    }
+}
+
+fn abort_now() -> ! {
+    check_correctness();
+    panic!(AbortNow)
+}
+
+thread_local! {
+    static ENTERED_ENTRY_POINT: Cell<usize> = Cell::new(0);
+}
+
+struct AbortNow;
+
+fn check_correctness() {
+    if ENTERED_ENTRY_POINT.with(|flag| flag.get()) == 0 {
+        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]"
+        );
+    }
+}
+
+/// **ALL THE STUFF INSIDE IS NOT PUBLIC API!!!**
+#[doc(hidden)]
+pub mod __export {
+    use proc_macro2::Span;
+    use quote::ToTokens;
+
+    // inspired by
+    // https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md#simple-application
+
+    pub trait DoubleSpanToTokens {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span);
+    }
+
+    pub trait DoubleSpanSingleSpan2 {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span);
+    }
+
+    pub trait DoubleSpanSingleSpan {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span);
+    }
+
+    impl<T: ToTokens> DoubleSpanToTokens for &T {
+        fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span) {
+            let mut ts = self.to_token_stream().into_iter();
+            let start = ts
+                .next()
+                .map(|tt| tt.span())
+                .unwrap_or_else(Span::call_site);
+            let end = ts.last().map(|tt| tt.span()).unwrap_or(start);
+            (start, end)
+        }
+    }
+
+    impl DoubleSpanSingleSpan2 for Span {
+        fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span) {
+            (*self, *self)
+        }
+    }
+
+    impl DoubleSpanSingleSpan for proc_macro::Span {
+        fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span) {
+            (self.clone().into(), self.clone().into())
+        }
+    }
+}
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..ccf6547
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,266 @@
+// 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)+) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
+        let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+
+        let diag = $crate::Diagnostic::double_spanned(
+            start,
+            end,
+            $level,
+            format!($fmt, $($args),*)
+        );
+        $crate::__pme__suggestions!(diag $($rest)*);
+        diag
+    }};
+
+    ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
+        let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+
+        let diag = $crate::Diagnostic::double_spanned(start, end, $level, $msg.to_string());
+        $crate::__pme__suggestions!(diag $($rest)*);
+        diag
+    }};
+
+    // span, message, no help
+    ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
+        let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+
+        $crate::Diagnostic::double_spanned(
+            start,
+            end,
+            $level,
+            format!($fmt, $($args),*)
+        )
+    }};
+
+    ($span:expr, $level:expr, $msg:expr) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
+        let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+
+        $crate::Diagnostic::double_spanned(start, end, $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::abort!($crate::proc_macro2::Span::call_site(), $($tts)*)
+    };
+}
+
+/// 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::emit_error!($crate::proc_macro2::Span::call_site(), $($tts)*)
+    };
+}
+
+/// 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)*) => {{
+        $crate::emit_warning!($crate::proc_macro2::Span()::call_site(), $($tts)*)
+    }};
+}
+
+#[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)*)
+    };
+}