liveBook · Manning

Syn::Error

As explained in Write Powerful Rust Macros

syn::Error is syn's error type for reporting parsing and syntax-processing failures with source spans and diagnostic messages.

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

How Write Powerful Rust Macros covers it

How deep it goes
Builds errors, attaches spans, converts them to tokens, and combines multiple failures; it stops short of replacing richer diagnostic frameworks.
Examples
Demonstrates invalid async signatures, forbidden Result returns, empty panic messages, and combined signature and statement errors.
What it assumes
Assumes Rust procedural-macro and Result familiarity while developing span-aware error handling from existing panic-based checks.
What you can do after
Diagnose/debug with it: return precise, source-pointed compile errors from procedural macros instead of unhelpful panic messages.
How it connects
Connects Result, procedural macros, TokenStream, source spans, ToTokens, and proc_macro_error.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Write Powerful Rust Macros. The section links point to the parts of the book it draws on.