Skip to content

feat: remove proc-macro-error3 in favor of syn::Error - #90

Open
anlavandier wants to merge 2 commits into
probe-rs:masterfrom
anlavandier:feat/remove-proc-macro-error3
Open

feat: remove proc-macro-error3 in favor of syn::Error#90
anlavandier wants to merge 2 commits into
probe-rs:masterfrom
anlavandier:feat/remove-proc-macro-error3

Conversation

@anlavandier

@anlavandier anlavandier commented Aug 11, 2026

Copy link
Copy Markdown

This PRs removes instances of proc-macro-error3s abort! and abort_call_site! and replaces them with the use of syn::Resut and syn::Error.

Why am I doing this

proc-macro-error3 was put there as a drop-in replacement for proc-macro-error2 which is unmaintained and contains code will be rejected from futures versions of the compiler.
While nothing at the moment leads me to believe that proc-macro-error3 will ever contain such code, it is still way more likely for proc-macro-error3 to become unmaintained over time than it is for syn. There also aren't really reasons to use it when syn has the necessary functionality and needs to be used in proc-macro crates anyway.
Dropping proc-macro-error3 will make embedded-test:

  • Less likely to run into the issues that existed with proc-macro-error2
  • Compile faster thanks to having one less crate to compile
  • Less vulnerable to supply-chain attacks. While I don't believe that the author of proc-macro-error3 has any ill intentions, people needed to switch quickly from one unmaintained is the perfect storm for someone willing to fork said crate and play the long game. Again I'm not accusing anybody of anything but as a downstream user of embedded-test through Ariel OS I worry about supply-chain attacks and removing proc-macro-error3 remove one such vector.

The solution proposed in this PR is the one chosen by other libs in the embedded ecosystem like pio-rs rp-rs/pio-rs#85 and defmt knurling-rs/defmt#1070

Testing

Successfully ran :

  • clippy on embedded-test and embedded-test-macros
  • cd tests-build && cargo test -- --test-threads 1

Signed-off-by: Antoine Lavandier <antoine.lavandier@inria.fr>
Signed-off-by: Antoine Lavandier <antoine.lavandier@inria.fr>
Comment on lines +19 to +23
let ident = attr
.path()
.get_ident()
.map(ToString::to_string)
.unwrap_or_default();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I decided to use the fact that match statement below has a _ => None to use .map(ToString::to_string).unwrap_or_default().

Comment on lines 50 to +60
impl TimeoutAttribute {
fn from_attr(attr: &Attribute) -> Self {
fn from_attr(attr: &Attribute) -> syn::Result<Self> {
match attr.parse_args::<TimeoutAttribute>() {
Ok(timeout_attr) => timeout_attr,
Ok(timeout_attr) => Ok(timeout_attr),
Err(e) => {
abort!(
attr,
"failed to parse `timeout` attribute. Must be of the form #[timeout(10)] where 10 is the timeout in seconds. Error: {}",
e
);
Err(syn::Error::new(
attr.span(),
format!(
"failed to parse `timeout` attribute. Must be of the form #[timeout(10)] where 10 is the timeout in seconds. Error: {}",
e
)))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is a good case study of what the majority of the changes look like. Functions that could previously panic! using abort!(x, y) have heir signature changed to syn::Result<> and the previously panicking path returns syn::Err::new(x.span(), y) instead.

Comment on lines +91 to +94
impl TryFrom<ItemFn> for FunctionWithAttributes {
type Error = syn::Error;

fn try_from(mut func: ItemFn) -> syn::Result<Self> {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here since I need to output syn::Result<> the From implementations that could panic have been changed to TryFrom<Error = syn::Error> impls.


impl MacroArgs {
pub(crate) fn parse(args: TokenStream) -> Result<Self, syn::Error> {
pub(crate) fn parse(args: TokenStream) -> syn::Result<Self> {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was done for consistency since syn::Result<X> is now common across the codebase.

&& self.macro_args.executor.is_some()
{
abort_call_site!(
return Err(syn::Error::new(Span::call_site(),

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

abort_call_site!(Y) are replaced with syn::Error::new(Span::call_site(), Y)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant