> [!NOTE]
>
> This is a maintained fork of
> [`proc-macro-error-2`](https://github.com/GnomedDev/proc-macro-error-2), which
> itself was a fork of
> [`proc-macro-error`](https://github.com/CreepySkeleton/proc-macro-error). The
> goal is to keep the crate maintained while preserving the original API and
> behavior as much as possible.
>
> Notable changes from `proc-macro-error` to `proc-macro-error-2`:
>
> - Upgraded `syn` to `2`.
> - Raised the MSRV to `1.61`.
> - Removed automatic nightly detection; use the `nightly` feature for improved
>   diagnostics.
>
> Notable changes in this fork compared to `proc-macro-error-2`:
>
> - Fixed the future-incompatibility warning from
>   [`rust-lang/rust#127909`](https://github.com/rust-lang/rust/issues/127909)
> - [#3](https://github.com/gamma0987/proc-macro-error3/pull/3) Fixed the args
>   expansion in macros missed the comma in the presence of trailing commas.
> - [#4](https://github.com/gamma0987/proc-macro-error3/pull/4) Fixed panics
>   when parsing `syn::Error` fails.
> - Supports `syn` v2 and `syn` v3 error conversion behind explicit Cargo
>   features. `syn3-error` is enabled by default; `syn2-error` is available for
>   crates that still parse with `syn` 2.
> - The changelog contains all notable changes

# Makes error reporting in procedural macros nice and easy

[![docs.rs](https://docs.rs/proc-macro-error3/badge.svg)](https://docs.rs/proc-macro-error3)
[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)

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, you can explicitly [append a dummy token stream][crate::dummy] to your
errors.

To achieve this, this crate serves as a tiny shim around
`proc_macro::Diagnostic` and `compile_error!`. It detects the most preferable
way to emit errors based on compiler's version. When the underlying diagnostic
type is finally stabilized, this crate will be simply delegating to it,
requiring no changes in your code!

So you can just use this crate and have _both_ some of `proc_macro::Diagnostic`
functionality available on stable ahead of time and your error-reporting code
future-proof.

```toml
[dependencies]
proc-macro-error3 = "3.0"
```

By default this enables the `syn3-error` feature, which provides
`From<syn::Error>` for this crate's `Diagnostic`. If your crate still uses `syn`
v2, disable default features and opt into `syn2-error` instead:

```toml
[dependencies]
proc-macro-error3 = { version = "3.0", default-features = false, features = ["syn2-error"] }
```

The legacy `syn-error` feature remains available as an alias for `syn3-error`.
Disable default features entirely if you do not need any `syn::Error` conversion
support.

_Supports rustc 1.61 and up_

[Documentation and guide][guide]

## Quick example

Code:

```rust
#[proc_macro]
#[proc_macro_error]
pub fn make_fn(input: TokenStream) -> TokenStream {
    let mut input = TokenStream2::from(input).into_iter();
    let name = input.next().unwrap();
    if let Some(second) = input.next() {
        abort! { second,
            "I don't like this part!";
                note = "I see what you did there...";
                help = "I need only one part, you know?";
        }
    }

    quote!( fn #name() {} ).into()
}
```

This is how the error is rendered in a terminal:

<p align="center">
<img src="https://user-images.githubusercontent.com/50968528/78830016-d3b46a80-79d6-11ea-9de2-972e8d7904ef.png" width="600">
</p>

And this is what your users will see in their IDE:

<p align="center">
<img src="https://user-images.githubusercontent.com/50968528/78830547-a9af7800-79d7-11ea-822e-59e29bda335c.png" width="600">
</p>

## Examples

### Panic-like usage

```rust
use proc_macro_error3::{
    proc_macro_error,
    abort,
    abort_call_site,
    ResultExt,
    OptionExt,
};
use proc_macro::TokenStream;
use syn::{DeriveInput, parse_macro_input};
use quote::quote;

// This is your main entry point
#[proc_macro]
// This attribute *MUST* be placed on top of the #[proc_macro] function
#[proc_macro_error]
pub fn make_answer(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    if let Err(err) = some_logic(&input) {
        // we've got a span to blame, let's use it
        // This immediately aborts the proc-macro and shows the error
        //
        // You can use `proc_macro::Span`, `proc_macro2::Span`, and
        // anything that implements `quote::ToTokens` (almost every type from
        // `syn` and `proc_macro2`)
        abort!(err, "You made an error, go fix it: {}", err.msg);
    }

    // `Result` has some handy shortcuts if your error type implements
    // `Into<Diagnostic>`. `Option` has one unconditionally.
    more_logic(&input).expect_or_abort("What a careless user, behave!");

    if !more_logic_for_logic_god(&input) {
        // We don't have an exact location this time,
        // so just highlight the proc-macro invocation itself
        abort_call_site!(
            "Bad, bad user! Now go stand in the corner and think about what you did!");
    }

    // Now all the processing is done, return `proc_macro::TokenStream`
    quote!(/* stuff */).into()
}
```

### `proc_macro::Diagnostic`-like usage

```rust
use proc_macro_error3::*;
use proc_macro::TokenStream;
use syn::{spanned::Spanned, DeriveInput, ItemStruct, Fields, Attribute , parse_macro_input};
use quote::quote;

fn process_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
    attrs
        .iter()
        .filter_map(|attr| match process_attr(attr) {
            Ok(res) => Some(res),
            Err(msg) => {
                emit_error!(attr, "Invalid attribute: {}", msg);
                None
            }
        })
        .collect()
}

fn process_fields(_attrs: &Fields) -> Vec<TokenStream> {
    // processing fields in pretty much the same way as attributes
    unimplemented!()
}

#[proc_macro]
#[proc_macro_error]
pub fn make_answer(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as ItemStruct);
    let attrs = process_attrs(&input.attrs);

    // abort right now if some errors were encountered
    // at the attributes processing stage
    abort_if_dirty();

    let fields = process_fields(&input.fields);

    // no need to think about emitted errors
    // #[proc_macro_error] will handle them for you
    //
    // just return a TokenStream as you normally would
    quote!(/* stuff */).into()
}
```

## 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 your macro happens to trigger a panic, no errors will be displayed. This is
  not a technical limitation but rather intentional design. `panic` is not for
  error reporting.

## MSRV policy

The MSRV is currently `1.61`, and this is considered a breaking change to
increase.

However, if an existing dependency requires a higher MSRV without a semver
breaking update, this may be raised.

## Motivation

Error handling in proc-macros sucks. There's not much of a choice today: you
either "bubble up" the error up to the top-level of the macro and convert it to
a [`compile_error!`][compl_err] invocation or just use a good old panic. Both
these ways suck:

- Former sucks because it's quite redundant to unroll a proper error handling
  just for critical errors that will crash the macro anyway; so people mostly
  choose not to bother with it at all and use panic. Simple `.expect` is too
  tempting.

    Also, if you do decide to implement this `Result`-based architecture in your
    macro you're going to have to rewrite it entirely once
    [`proc_macro::Diagnostic`][] is finally stable. Not cool.

- Later sucks because there's no way to carry out the span info via `panic!`.
  `rustc` will highlight the invocation itself but not some specific token
  inside it.

    Furthermore, panics aren't for error-reporting at all; panics are for
    bug-detecting (like unwrapping on `None` or out-of-range indexing) or for
    early development stages when you need a prototype ASAP so error handling
    can wait. Mixing these usages only messes things up.

- There is [`proc_macro::Diagnostic`][] which is awesome but it has been
  experimental for more than a year and is unlikely to be stabilized any time
  soon.

    This crate's API is intentionally designed to be compatible with
    `proc_macro::Diagnostic` and delegates to it whenever possible. Once
    `Diagnostics` is stable this crate will **always** delegate to it, no code
    changes will be required on user side.

That said, we need a solution, but this solution must meet these conditions:

- It must be better than `panic!`. The main point: it must offer a way to carry
  the span information over to user.
- It must take as little effort as possible to migrate from `panic!`. Ideally, a
  new macro with similar semantics plus ability to carry out span info.
- It must maintain compatibility with [`proc_macro::Diagnostic`][] .
- **It must be usable on stable**.

This crate aims to provide such a mechanism. All you have to do is annotate your
top-level `#[proc_macro]` function with `#[proc_macro_error]` attribute and
change panics to [`abort!`]/[`abort_call_site!`] where appropriate, see [the
Guide][guide].

## Disclaimer

Please note that **this crate is not intended to be used in any way other than
error reporting in procedural macros**, use `Result` and `?` (possibly along
with one of the many helpers out there) for anything else.

<br>

### License

<sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
</sup>

<br>

<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.
</sub>

[compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html
[`proc_macro::Diagnostic`]:
    https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html
[crate::dummy]:
    https://docs.rs/proc-macro-error3/latest/proc_macro_error3/dummy/index.html
[`abort_call_site!`]:
    https://docs.rs/proc-macro-error3/latest/proc_macro_error3/macro.abort_call_site.html
[`abort!`]:
    https://docs.rs/proc-macro-error3/latest/proc_macro_error3/macro.abort.html
[guide]: https://docs.rs/proc-macro-error3
