Proc-macro-error API cannot be used outside of `entry_point` invocation

As best I can tell this error:

proc-macro-error API cannot be used outside of `entry_point` invocation, perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]

is caused by this usage in a function that is indeed outside of the proc-macro-attribute entry point:

syn::parse_quote_spanned!(span=> #param: 'a)

The documentation is silent on where this can be used... is my println!(..) spelunking correct or is there something else possibly triggering this error?

If parse_quote_spanned! is the source of the API error, what function chain is equivalent, i.e functions that can be used outside of the entry_point?

Appreciate any hints or tips.

In fact as best I can tell, this API error is a side effect of abort_call_site!("message"). For some reason the "message" does not percolate up.

So, parse_quote!(…) (and ditto for the spanned variant) is kind of a shorthand for:

::syn::parse2(quote{,_spanned}! ( [span=>]

So this already answers the what function chain is equivalent question :slightly_smiling_face:

From there, if you happen to feed code to quote! that could not be syn::parsed as the target type, parse_quote…! then panics.

You also seem to be using the proc-macro-error (quite heavyweight)[1] error reporting framework. Such framework works by wrapping the proc-macro entry-point calls inside catch_unwind! scopes (to catch panics, à la C++ exceptions), and using helper thread-local storage adjacent to the catch_unwind scoping.

Thus, if your abort_call_site!() happens in a function that was not transitively called by a #[proc-macro-error]-annotated proc-macro, or if it happened from within a helper thread, then the companion thread-local storage won't be in the expected "scoped" state, hence yielding that error.

  1. I have very mixed feelings about the idea behind that crate (which is nonetheless a well-written crate): it involves mixing the proc-macro framework from cargo/rust with its own error-reporting framework, and the whole thing is achieved through global state, panic-catching, and worse: helper procedural macros. If proc-macros have already a rather steep compile-time cost, nesting them, dependency-wise, just aggravates the issue. I don't see it being worth it when syn::Error::new_spanned(…).to_compile_error() yields already 95% good error messages. Embedding a slow-to-compile cognitive-burden-to-learn and with-implementation-restrictions framework for that 5%-improvement for the error messages is so not worth it, in my opinion. ↩︎

1 Like

Thanks for the detailed insights. I take your point about proc-macro-error, and I think I'll try to move away from that - I have a peculiar error that only shows up in a third party crate - all unit and integration tests in the proc-macro crate are green, so I'm beginning to think outside the box and this is one observation I'll take on board.