You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
--pretty=expanded is an incredibly useful debugging tool for macros. The change in rustc 1.19 to stop supporting unstable command-line options on the stable/beta compilers makes it all the more important to stabilize unstable options that people use, and this seems like it easily qualifies.
Much like --emit mir, this should not make any commitments about the output, only that the option should continue to exist. In particular, I'd even suggest making it explicitly clear that there's no commitment for the output to compile.
I strongly don't want to do this. The generated code is not guaranteed to compile (because hygienic names are not reflected in the generated source text), it means a big chunk of compiler code (pretty printing) is now exposed to stable users, and I worry about bugs, etc. in that code.
I worry that this will encourage tools to try and use that output code, which is absolutely the wrong thing to do.
For debugging macros, we should be able to use expansion info in spans, plus some output saved from macro expansion to give a much better tool - look at every stage of expansion, not just the start and end, have def/ref info for each stage, etc.
@nrc I'd love to see an even more capable mechanism, absolutely, and the idea of stepping through macro expansion step-by-step sounds incredible. But in the interim, --pretty=expanded is what we have for macro debugging, which means stable users have approximately nothing.
If you want to discourage tools from using it, stick an intentional line at the top explaining that the output format isn't stable and prevent it from compiling. But I don't think it's reasonable to take away the only mechanism stable users have for macro debugging, offer no recourse, and not yet have another solution available.
Now, that said, that does mean this will still break cbindgen and other tools which apparently process this code. And that seems quite unfortunate as well, but perhaps more justifiable. But right now, I'm a lot more worried about what to tell stable users who ask "how do I debug my macros?".
Reacted by Alex Burka, Peter Atashian, kennytm, Tim, Gio d'Amelio, Marc-André Lureau, Bart Massey, Jeff Hiner, bb010g, Gabriel Linder and 3 more
@nrc Every-stage-expansion is useful, but just like we have both -Zdump-mir and --emit mir, I don't think that precludes the introduction of --emit expanded/--print expanded.
But right now, I'm a lot more worried about what to tell stable users who ask "how do I debug my macros?".
We tell them to use nightly. Switching compiler with rustup is so easy, that I don't think a stable requirement is a reason to stabilise an otherwise unstable feature.
Reacted by Ildar Sagdejev
Reacted by Gabriel Linder, Tobias Berger, Benjamin Valpey, Sean Rester and mihalious
I feel like expanded AST is different from mir, because no-one parses the MIR code and expects it to compile (at least as Rust, it would compile as its own language).
@nrc using nightly doesn't always work, as the involving macro may change between rust versions (consider the difference of thread_local! between stable and nightly.)
Reacted by Jake Goulding, bb010g, Gabriel Linder, Martin Nordholts and Ildar Sagdejev
I was wondering if the output isn't compilable, could it at least be parseable? Related to #47287 I came across an issue where a macro expansion results in unparseable output. In particular, I was trying to use cargo expand on the cargo source tree, and rustfmt chokes on this idiom. Not a big deal, one can work around it by not using rustfmt, but unformatted macro expansion can be difficult to read.
// Worksfnf1() -> bool{macro_rules! try(( $ e : expr ) => (match $ e {Some( e ) => e ,None => returnfalse,}));
try!(Some(42)) == 42}// Expanded version doesn't workfnf2() -> bool{matchSome(42){Some( e ) => e ,None => returnfalse,} == 42}// Could be OK with parenthesis (at least in this case)fnf3() -> bool{(matchSome(42){Some( e ) => e ,None => returnfalse,}) == 42}
For debugging macros, we should be able to use expansion info in spans, plus some output saved from macro expansion to give a much better tool - look at every stage of expansion, not just the start and end, have def/ref info for each stage, etc.
@nrc can you please provide more details about how we can retrieve such information (if this is possible)?
Note that the situation needs some kind of solution at the moment. --pretty=expanded is used by cbindgen, which helps gluing together WebRender with Gecko as well as powering other crates, like wgpu-bindings.
If stabilizing the pretty output is not an option, what would be the right way to proceed with making cbindgen robust? cc @eqrion
Can this be used with Cargo.toml-based crates, rather than just with a single .rs file, and if so, how, please? (RUSTCFLAGS="-Zunpretty=expanded" cargo +nightly check --bin a-binary-crate doesn't generate anything.)
If this generates the same code as cargo expand (minus formatting), then this has a problem: The generated code is NOT the same as what gets compiled with cargo build and friends. cargo expand may generate code that fails cross-crate lints originating in, or hoping to affect, macros. But cargo build compiles and silently ignores such cross-crate lints. See Forbidding lints doesn't really work in macros #110613.
A cherry on top would be if the output were also stable, but that's not technically needed (I don't think), since:
Rust's stability guarantees mean that correct code's behavior shouldn't change across versions,
And thus semantic equivalence (the one mentioned before) should also make the behavior of the expanded code stable.
That is: it would be really cool if the output of the expansion tool were stable. But since what we want is to be able to reason about macro-calling code, by expanding it and examining the resulting source, semantic equivalence of code and the tool's macro expansion of it suffice for this reasoning to be stable across Rust versions.
Activity
shepmaster commentedon Jul 20, 2017
For usage in the playground, it would be lovely if it was actually
--emit something, perhaps--emit macro-expanded?nrc commentedon Aug 10, 2017
I strongly don't want to do this. The generated code is not guaranteed to compile (because hygienic names are not reflected in the generated source text), it means a big chunk of compiler code (pretty printing) is now exposed to stable users, and I worry about bugs, etc. in that code.
I worry that this will encourage tools to try and use that output code, which is absolutely the wrong thing to do.
For debugging macros, we should be able to use expansion info in spans, plus some output saved from macro expansion to give a much better tool - look at every stage of expansion, not just the start and end, have def/ref info for each stage, etc.
joshtriplett commentedon Aug 10, 2017
@nrc I'd love to see an even more capable mechanism, absolutely, and the idea of stepping through macro expansion step-by-step sounds incredible. But in the interim,
--pretty=expandedis what we have for macro debugging, which means stable users have approximately nothing.If you want to discourage tools from using it, stick an intentional line at the top explaining that the output format isn't stable and prevent it from compiling. But I don't think it's reasonable to take away the only mechanism stable users have for macro debugging, offer no recourse, and not yet have another solution available.
Now, that said, that does mean this will still break cbindgen and other tools which apparently process this code. And that seems quite unfortunate as well, but perhaps more justifiable. But right now, I'm a lot more worried about what to tell stable users who ask "how do I debug my macros?".
kennytm commentedon Aug 12, 2017
@nrc Every-stage-expansion is useful, but just like we have both
-Zdump-mirand--emit mir, I don't think that precludes the introduction of--emit expanded/--print expanded.nrc commentedon Aug 21, 2017
We tell them to use nightly. Switching compiler with rustup is so easy, that I don't think a stable requirement is a reason to stabilise an otherwise unstable feature.
nrc commentedon Aug 21, 2017
I feel like expanded AST is different from mir, because no-one parses the MIR code and expects it to compile (at least as Rust, it would compile as its own language).
kennytm commentedon Aug 21, 2017
@nrc using nightly doesn't always work, as the involving macro may change between rust versions (consider the difference of
thread_local!between stable and nightly.)ehuss commentedon Jun 25, 2018
I was wondering if the output isn't compilable, could it at least be parseable? Related to #47287 I came across an issue where a macro expansion results in unparseable output. In particular, I was trying to use cargo expand on the cargo source tree, and rustfmt chokes on this idiom. Not a big deal, one can work around it by not using rustfmt, but unformatted macro expansion can be difficult to read.
fedochet commentedon Aug 14, 2018
@nrc can you please provide more details about how we can retrieve such information (if this is possible)?
kvark commentedon Jan 18, 2019
Note that the situation needs some kind of solution at the moment.
--pretty=expandedis used by cbindgen, which helps gluing together WebRender with Gecko as well as powering other crates, like wgpu-bindings.If stabilizing the pretty output is not an option, what would be the right way to proceed with making
cbindgenrobust? cc @eqrioneqrion commentedon Jan 18, 2019
Assuming stabilizing the output is not the right path forward, I believe something like my
rust-ffiprototype is a good path forward.I've been too busy to work on getting it to a MVP though.
nrc commentedon Jan 18, 2019
There's also
cargo-expand. We'll be looking at adding some support to the RLS which might be a better path to stabilisation that--pretty=expanded7 remaining items
jyn514 commentedon May 10, 2023
Note that
--pretty=expandedhas since been renamed to-Zunpretty=expanded: #83491I am not sure why this was tagged T-lang. It seems pretty clearly T-compiler to me; it does not affect the syntax or semantics of the language.
[-]Stabilize --pretty=expanded[/-][+]Stabilize -Zunpretty=expanded[/+]Added `rust_unpretty_aspect` and `rust_unpretty` rules (#2356)
fix: rust: removed deprecated rustc arguments
fix: removed deprecated rustc arguments
valera-rozuvan commentedon Feb 21, 2025
For anyone that comes here from old resources (such as [1], [2]), and wondering how to actually use this in 2025:
PS: Make sure to get
nightlyfirst by doingrustup toolchain install nightly.[1] SO: What exactly does '#[derive(Debug)]' mean in Rust?
[2] What happened to
--pretty?peter-lyons-kehl commentedon Nov 14, 2025
Can this be used with
Cargo.toml-based crates, rather than just with a single.rsfile, and if so, how, please? (RUSTCFLAGS="-Zunpretty=expanded" cargo +nightly check --bin a-binary-cratedoesn't generate anything.)If this generates the same code as
cargo expand(minus formatting), then this has a problem: The generated code is NOT the same as what gets compiled withcargo buildand friends.cargo expandmay generate code that fails cross-crate lints originating in, or hoping to affect, macros. Butcargo buildcompiles and silently ignores such cross-crate lints. See Forbidding lints doesn't really work in macros #110613.aytey commentedon Nov 17, 2025
cargo expandliterally callscargowith-Zunpretty=expanded, see: https://github.com/dtolnay/cargo-expand/blob/48e736617b6e054ba0f5cf68fc4f3b13e8d39a32/README.md?plain=1#L17ojeda commentedon Nov 17, 2025
@rustbot label: +A-rust-for-linux
felix91gr commentedon Apr 17, 2026
Hi ^^
I come to add my 2c that if a tool like the
-Zunpretty=expandedflag existed, but with the added perks of:Would help quite a bit for the purposes of Safety Critical Rust: Safety-Critical-Rust-Consortium/safety-critical-rust-consortium#583, especially since this would make assessing Rust code for safety critical contexts more accessible :)
A cherry on top would be if the output were also stable, but that's not technically needed (I don't think), since:
That is: it would be really cool if the output of the expansion tool were stable. But since what we want is to be able to reason about macro-calling code, by expanding it and examining the resulting source, semantic equivalence of code and the tool's macro expansion of it suffice for this reasoning to be stable across Rust versions.