我该如何查看导致编译错误的宏展开代码?

91

我遇到了一个涉及宏的编译错误:

<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/parser.rs:30:42: 37:11 note: expansion site
error: aborting due to previous error

不幸的是,该宏是递归的,因此很难弄清楚编译器在抱怨什么,而且似乎行号是针对扩展宏而不是我的代码。

我如何查看扩展的宏?是否有一个标志可以传递给rustc(或者更好的是cargo),以便将其转储出来?

(这个宏来自rust-mdo,但我认为这并不重要。)

4个回答

105

cargo rustc --profile=check -- -Zunpretty=expanded,但更简洁的选择是使用cargo-expand crate。它提供了一个Cargo子命令cargo expand,用于打印宏展开的结果。它还将扩展后的代码通过rustfmt进行格式化,通常比rustc的默认输出结果更易读。

运行cargo install cargo-expand进行安装。


cargo install cargo-expand --features=prettyprint/regex-fancy会略微慢一些,但避免了对c++依赖,因此更有可能构建成功。 - Squirrel
cargo-expand 不依赖于 prettyprint 或任何 C++ 依赖项。 - dtolnay
1
你应该提到你是 crate 的作者。 - SharedRory
2
现在已经是2021年了,情况有所改变。您现在可以使用命令:rustc -Zunpretty=expanded some.rs。有关更多详细信息,请参见Enselic的答案。 - at54321

51

是的,您可以向 rustc 传递一个特殊标志,称为 --pretty=expanded:

% cat test.rs
fn main() {
    println!("Hello world");
}
% rustc -Z unstable-options --pretty=expanded test.rs
#![feature(no_std)]
#![no_std]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate "std" as std;
fn main() {
    ::std::old_io::stdio::println_args(::std::fmt::Arguments::new_v1({
                                                                         static __STATIC_FMTSTR:
                                                                                &'static [&'static str]
                                                                                =
                                                                             &["Hello world"];
                                                                         __STATIC_FMTSTR
                                                                     },
                                                                     &match ()
                                                                          {
                                                                          ()
                                                                          =>
                                                                          [],
                                                                      }));
}

然而,您需要通过传递-Z unstable-options来首先允许它。

自Rust 1.1以来,您可以像这样将这些参数传递给Cargo:

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

8
截至1.19版本,这个命令cargo rustc -- -Z unstable-options --pretty=expanded现在只能在夜间版中使用。 - lncr
2
为什么它只在夜间版中? - Bogdan Mart
3
因为它使用了一个不稳定的选项,但是不用担心,你可以轻松地使用它。运行 rustup install nightly,然后运行 rustup run nightly cargo rustc -- -Z unstable-options --pretty=expanded - grooveplex
7
那么,这项能力三年来(而且还在继续)从未被“稳定”? - jhfrontz
1
可能不是因为稳定性的问题,而更多是因为他们不想承诺支持它。 - Tumbleweed53
@jhfrontz 很多功能都没有稳定下来,因为这意味着即使他们弃用它,它仍然可用,并且除了作为调试或内部功能之外不应该被使用。-Z timings-Z unstable-options --pretty=expanded,大多数 rustfmt lint 仅适用于夜间版。 - Alex Huszagh

41
如果您想在编译之前查看扩展代码,可以使用 rust-analyzer(用于 Rust 语言的 VS Code 扩展)的 Expand Macro Recursively 功能。

enter image description here


15

nightly-2021-07-28开始,您需要像这样传递-Zunpretty=expanded而不是-Zunstable-options --pretty=expanded

% rustc -Zunpretty=expanded test.rs

或者:
% cargo rustc -- -Zunpretty=expanded

相关的 rustc 提交

通过这个提交--pretty参数已经在nightly-2021-07-28版本中被移除。 支持-Zunpretty=expanded已经在nightly-2018-01-24版本中添加,详见此提交


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接