How does this macro optimize?

⚓ Rust    📅 2025-09-20    👤 surdeus    👁️ 8      

surdeus

Warning

This post was published 41 days ago. The information described in this article may have changed.

I have the following macro:

macro_rules! a {
    ($item:item) => {
        #[b]
        $item
    }
}

I am nesting it 10 times:

a!(a!(a!(a!(a!(a!(a!(a!(a!(a!(
    struct Foo;
))))))))));

How does it optimize? Is it like this:

#[proc_macro]
fn a(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as Item);

   quote! { #[b] #item }
}

With 10 nested calls to a, the same macro input will be parsed and quoted 10 times in a row.

Or does the compiler optimize it to do all the work in 1 go:

#[proc_macro]
fn a(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as Item);

   quote! { #[b] #[b] #[b] #[b] #[b] #[b] #[b] #[b] #[b] #[b] #item }
}

The above is a very simplified example of the real use-case: I am making a crate derive_aliases and I am currently implementing it as a proc macro. I generate all the derives in a single go. I realized I can implement my crate using declarative macros instead, nesting the user's input in 10-20 plus calls to the macros. I have a feeling this will be much slower, but I'm wondering if the compiler has any optimization passes for macros which would make the declarative version faster

Just imagine this: another macro b!() nests the $item in 20 calls to a!(). b!() is called thousands of times in the code-base. These are the numbers

Or alternatively, b!() is a proc macro and does all of the work for 20 calls in a single pass. All logic for a!() is inlined in a single macro call. No nesting. $item is parsed just once.

I have a feeling the 2nd version will have much better compile-time speeds

2 posts - 2 participants

Read full topic

🏷️ Rust_feed