syn::Error is the Result-compatible error type for procedural macros. It carries a diagnostic message and a source span, so compilation errors point to the relevant syntax instead of only to the macro invocation. section 7.9.1 section 7.12
Create an error with syn::Error::new by supplying a span and message. Use new_spanned when the diagnostic should cover anything implementing ToTokens, such as a function token together with its name. Convert the error with to_compile_error before returning the resulting TokenStream. section 7.9.1 section 7.10
Rejecting a non-async function
if input.sig.asyncness.is_none() { let msg = "the `async` keyword is missing from the function declaration"; return Err(syn::Error::new_spanned(input.sig.fn_token, msg)); } A macro can then convert the error into compile-error tokens. The diagnostic identifies the missing keyword at the function declaration rather than producing a vague panic. section 7.10
Returning Result makes failure paths explicit throughout parsing and transformation. When several independent checks fail, combine errors before converting them, allowing more than one diagnostic to reach the user. syn::Error avoids the weak source location and message produced by ordinary macro panics. section 7.9.1 section 7.9.1
Listing 7.19 syn error handling (partial code from lib.rs)
// other imports
use syn::spanned::Spanned; #1
fn signature_output_as_result(ast: &ItemFn)
-> Result<ReturnType, syn::Error> {
let output = match ast.sig.output {
// default return code...
ReturnType::Type(_, ref ty) => {
if ty.to_token_stream().to_string().contains("Result") {
return Err(
syn::Error::new(
ast.sig.span(), #2
format!(
"this macro can only be applied to a function
that does not return a Result. Signature: {}",
quote!(#ty) #3
)
)
);
}
quote! {
-> Result<#ty, String>
}
}
};
Ok(syn::parse2(output).unwrap())
}
#[proc_macro_attribute]
pub fn panic_to_result(_a: TokenStream, item: TokenStream) -> TokenStream {
// other code
match signature_output_as_result(&ast) { #4
Ok(output) => ast.sig.output = output,
Err(err) => return err.to_compile_error().into()
};
// other code
}
Inspect a complete signature check that constructs syn::Error with the function span, formatted type information, and a precise compile-time message. section 7.9.1
