How do I see the expanded macro code that's causing my compile error?

DebuggingRustRust MacrosRust Proc-MacrosRust Decl-Macros

Debugging Problem Overview

I have a compile error involving a macro:

<mdo macros>:6:19: 6:50 error: cannot move out of captured outer variable in an `FnMut` closure
<mdo macros>:6 bind ( $ e , move | $ p | mdo ! { $ ( $ t ) * } ) ) ; (
<mdo macros>:1:1: 14:36 note: in expansion of mdo!
<mdo macros>:6:27: 6:50 note: expansion site
<mdo macros>:1:1: 14:36 note: in expansion of mdo!
<mdo macros>:6:27: 6:50 note: expansion site
<mdo macros>:1:1: 14:36 note: in expansion of mdo!
src/ 37:11 note: expansion site
error: aborting due to previous error

Unfortunately, the macro is recursive so it's hard to figure out what the compiler is complaining about, plus it seems like the line numbers are for the expanded macro rather than my code.

How can I see the expanded macro? Is there a flag I can pass to rustc (or even better, cargo) to dump this out?

(This macro is from rust-mdo, though I don't think it matters.)

Debugging Solutions

Solution 1 - Debugging

cargo rustc --profile=check -- -Zunpretty=expanded, but a more concise alternative is the cargo-expand crate. It provides a Cargo subcommand cargo expand which prints the result of macro expansion. It also passes the expanded code through rustfmt which generally results in much more readable code than the default output from rustc.

Install by running cargo install cargo-expand.

Solution 2 - Debugging

Yes, you can pass a special flag to rustc, called --pretty=expanded:

% cat
fn main() {
    println!("Hello world");
% rustc -Z unstable-options --pretty=expanded
use std::prelude::v1::*;
extern crate "std" as std;
fn main() {
                                                                         static __STATIC_FMTSTR:
                                                                                &'static [&'static str]
                                                                             &["Hello world"];
                                                                     &match ()

You need to allow it first, however, by passing -Z unstable-options.

Since Rust 1.1 you can pass these arguments to Cargo, like this:

cargo rustc -- -Z unstable-options --pretty=expanded

Solution 3 - Debugging

Starting with nightly-2021-07-28, one must pass -Zunpretty=expanded instead of -Zunstable-options --pretty=expanded, like this:

% rustc -Zunpretty=expanded


% cargo rustc -- -Zunpretty=expanded
Relevant rustc commits

The --pretty argument was removed from nightly-2021-07-28 via this commit. Support for -Zunpretty=expanded was added to nightly-2018-01-24 via this commit.

Solution 4 - Debugging

If you want to see the expanded code even before compiling, you can use Expand Macro Recursively feature of rust-analyzer (a vscode extension for Rust language).

enter image description here


All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCasparView Question on Stackoverflow
Solution 1 - DebuggingdtolnayView Answer on Stackoverflow
Solution 2 - DebuggingVladimir MatveevView Answer on Stackoverflow
Solution 3 - DebuggingEnselicView Answer on Stackoverflow
Solution 4 - DebuggingKrishnaView Answer on Stackoverflow