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 will succeed.
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
)
Diagnostic type
Diagnostic
type is intentionally designed to be API compatible with [proc_macro2::Diagnostic
].
Not all API is implemented, only the part that can be reasonably implemented on stable.