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.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.