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'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]
attribute. You'll just get a
panic otherwise, no errors will be shown.
For most of the time you will be using macros.
Very much panic-like usage - abort execution and show the error. Expands to !
(never type).
Shortcut for abort!(Span::call_site(), ...)
. Expands to !
(never type).
proc_macro::Diagnostic
-like usage - emit the error but do not abort the macro.
The compilation will fail nonetheless. Expands to ()
(unit type).
Shortcut for emit_error!(Span::call_site(), ...)
. Expands to ()
(unit type).
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.
Shortcut for emit_warning!(Span::call_site(), ...)
. Expands to ()
(unit type).
Build instance of Diagnostic
in format-like style.
Syntax
All the macros have pretty much the same syntax:
abort!(single_expr)
Shortcut for `Diagnostic::from().abort()`
2. ```ignore
abort!(span, message)
Shortcut for Diagnostic::spanned(span, message.to_string()).abort()
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:
#[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.