Proc macro debugging tricks

  1. cargo expand

  2. I have always struggled debugging procedural macros. Then I found this techniques:

pub fn my_macro(input: TokenStream) -> TokenStream {
  ...
  let out: TokenStream = .... ;
  panic!("{}", out);
  out
}

The cool thing here is: when you want to actually use the macro, comment out the panic! line.

When you get a weird compiler error due to macro generated code, and you are wondering 'wtf did this proc macro generate' ? Uncomment the panic! line.

  1. If others have cool proc macro debugging tricks, I am interested in hearing more.

I have no experience with debugging proc macros myself, but I imagine it could be possible - on a nightly compiler - to use this API to generate nice debugging information that doesn't stop any further compilation. Presumably, one could even permanently integrate emission of such debug information under a crate feature (properly documented to be unstable, nightly-only and intended for debugging purposes only) into a procedural macros crate.

I normally take a bottom-up approach where I'll implement one part of the proc-macro in its own function or ToTokens impl then write tests that assert the tokens I got are exactly what I expected.

That way, instead of reactively debugging things, you proactively make sure your code generates the expected tokens.

1 Like

I believe the Diagnostic API is intended for emitting the normal hint/warn/error messages that the Rust compiler would use to indicate compile errors.

I guess you could use it as a form of println!() debugging akin to OP's panic!() which doesn't abort execution, but that feels like you are misusing the feature.

I'd compare this kind of behavior to what you get when you're activating trace_macros, which is just an ordinary dignostic as well, more precisely a note:

note: trace_macro
 --> src/lib.rs:9:1
  |
9 | foo!(qux);
  | ^^^^^^^^^
  |
  = note: expanding `foo! { qux }`
  = note: to ``

So I do feel like it's legitimate to - e.g. conditionally (under a feature flag) - emit a note of this style through the Diagnostic API.

Posted a bunch of tips over:

Screen Shot 2021-12-26 at 16.21.37
link

2 Likes

@Yandros : Thanks for sharing; really nice how you break down macro errors into different classes of errors.

1 Like

Maybe you could add those tips to Debugging - The Little Book of Rust Macros to make it easier for others to find them?

1 Like

Why can't you just write dbg!(out) like with regular program?

proc macro can output text on screen. Not a good idea to supply something like that to others, but works well for debugging.

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.