Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

forward_attributes

API reference on docs.rs: forward_attributes.

forward_attributes turns ordinary outer attributes into an argument envelope for any item-position function-like macro. The receiving macro decides what the attributes mean.

You write Roughly expands to
#[forward_attributes]
#[derive(Debug, PartialEq)]
strutuct! {
    State { Ready, Waiting }
}

fn main() {
    assert_eq!(State::Ready, State::Ready);
    assert_eq!(format!("{:?}", State::Waiting), "Waiting");
}
strutuct! {
    #[derive(Debug, PartialEq)]
    ;
    State { Ready, Waiting }
}

fn main() {
    assert_eq!(State::Ready, State::Ready);
    assert_eq!(format!("{:?}", State::Waiting), "Waiting");
}

The semicolon distinguishes invocation-wide attributes from attributes that were already attached to the first object in the macro input. strutuct! and emmun! interpret the left side as inherited attributes and configuration; local attributes on the right retain their branch-specific meaning.

Why the invocation is enough

A function-like macro invocation in item position is already an attribute-compatible item shell. forward_attributes therefore does not need to invent a dummy struct: it parses only that shell, removes its outer attributes, and puts them at the front of the invocation’s existing token group. Rust still leaves the receiving macro’s private contents opaque.

This is specifically an item-position bridge. It does not make a macro call in type, pattern, or nested expression position into a target for an attribute procedural macro.

Expansion order

forward_attributes must be the first active attribute. An active attribute written before it may expand or fail before forwarding gets a turn:

You write What Rust sees first
#[derive(Debug)]
#[forward_attributes]
strutuct! { TooLate { A, B } }

fn main() {}
// `derive` runs before `forward_attributes`
// can move it into the macro input.
compile_error!(
    "derive may only be applied to structs, enums and unions"
);

Inert attributes such as documentation may precede it and are forwarded too.

Opaque input

Only the function-like invocation shell is parsed. Its delimited input remains an opaque token stream and may use any private syntax accepted by the receiving macro. The input must still be tokenizable and have balanced delimiters.

Macros opt into this convention by parsing:

zero or more outer attributes ; ordinary macro input

There is deliberately no universal meaning attached to those attributes.