[][src]Crate proc_macro_error

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 to your errors.

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.
  • Temporary incompatible with proc_macro_hack, unfortunately. No worries, some highly trained people are working on it!

Guide

Macros

First of all - all the emitting-related API must be used within a function annotated with #[proc_macro_error] attribute. You'll just get a panic otherwise, no errors will be shown.

Most of the time you want to use the 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. This example is not tested
    abort!(single_expr)

    Shortcut for Diagnostic::from(expr).abort(). There's no way to attach notes in this form!

  2. This example is not tested
    abort!(span, message)

    The first argument is an expression the span info should be taken from. It can be either

    The second argument is the error message, it must implement ToString.

  3. This example is not tested
    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 and 3 forms. Those are essentially shortcuts for macro!(Span::call_site(), args...).

diagnostic! requires Level instance between span and second argument (1 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:

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

  1. Every macro can have "note" attachments (only 2 and 3 form).
This example is not tested
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:

    This example is not tested
    #[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.

    Please note: 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.

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.

Re-exports

pub use crate::dummy::append_dummy;
pub use crate::dummy::set_dummy;

Modules

dummy

Facility to emit dummy implementations (or whatever) in case an error happen.

Macros

abort

Abort proc-macro execution right now and display the error.

abort_call_site

Shortcut for abort!(Span::call_site(), msg...). This macro is still preferable over plain panic, panics are not for error reporting.

diagnostic

Build Diagnostic instance from provided arguments.

emit_call_site_error

Shortcut for emit_error!(Span::call_site(), ...). This macro is still preferable over plain panic, panics are not for error reporting..

emit_call_site_warning

Shortcut for emit_warning!(Span::call_site(), ...).

emit_error

Emit an error while not aborting the proc-macro right away.

emit_warning

Emit a warning. Warnings are not errors and compilation won't fail because of them.

Structs

Diagnostic

Represents a single diagnostic message

Enums

Level

Represents a diagnostic level

Traits

OptionExt

This traits expands Option with some handy shortcuts.

ResultExt

This traits expands Result<T, Into<Diagnostic>> with some handy shortcuts.

Functions

abort_if_dirty

Abort macro execution and display all the emitted errors, if any.

Attribute Macros

proc_macro_error