Something went wrong with stringify

Hi there! My tries of translating some tokens to assembler ended up with an error. Here's the cizz code:


macro_rules! p {
    (unit $i:ident() {$($body:tt)*}$($rest:tt)*) => {

    (#nop $($rest:tt)*) => {nop $crate::p!{$($rest)*}};

pub macro index($($body:tt)*) {stringify!{$crate::p!{$($body)*}}}

and main code:

extern crate cizz as c;
use c::index as cizz;

fn main() {
    cizz! {
        unit start() {

This code prints $crate :: p! { unit start() { # nop } }, not


expected by me.

Am i doing something wrong with stringify?

The evaluation order of nested built-in macros is… somewhat arbitrary. Macros aren't always expanded from the innermost (or outermost) level of nesting like regular function calls are. The problem is that in order to be useful, some macros should get input that is already pre-expanded, while some others are expected to work on the "raw" AST. This prompted the language designers to make built-in macros expand in a special order relative to each other, and this mostly works just fine for simple invocations. If heavy nesting is involved, though, it can lead to surprising edge cases.

(Note that stringify!() alone won't ever produce the expected output with the newlines, because token stream stringification doesn't respect whitespace.)

1 Like

I was under the assumption that most macros expand the outermost macro first, and under this assumption op's result makes sense since stringify! is stringifying the tokens passed to it rather than the macro expression. What are the expections to this rule though? I think I remember something about doc attribute macros eagerly expanding concat!/include_str!, but those seem particular cases with built-in attribute macros.

1 Like

I don't know the exact list by heart, but this seems to point to the relevant parts of rustc.

1 Like