Trouble with -Z macro-backtrace

I'm debugging a proc-macro and can't seem to follow the advice that rust is giving me. Here is the tail end of an error message:

   = note: this error originates in the macro `polygraph_macro::schema` (in Nightly builds, run with -Z macro-backtrace for more info)

More info sounded great so I tried to follow the advice:

$ cargo +nightly test -Z macro-backtrace
error: unknown `-Z` flag specified: macro-backtrace

Am I doing something wrong, or is the error message itself in error? :frowning:

I think you might need the following to avoid having cargo-test process the argument:

cargo +nightly test -- -Z macro-backtrace

The -Z macro-backtrace is not a flag for cargo, nor for the integration tests binary, but for rustc.


The command

RUSTFLAGS=-Zmacro-backtrace cargo …

is the best way to achieve this.

  • If the cargo command is something as simple as check (or checking the unit tests), then you can run

    cargo rustc -- -Zmacro-backtrace # --cfg test # (to check the unit tests)

    This may be a bit faster to compiler since it won't change the RUSTFLAGS used to compile the dependencies, thus not invalidating the cached compilation artifacts for them.

An unstable flag

Finally, note that -Z macro-backtrace is an unstable feature.

If you are developing on a machine with no nightly available, but want really hard to be able to debug these macros, then you can use the super unstable RUSTC_BOOTSTRAP=1 to temporarily imbue your current cargo toolchain with unstable capabilities. But do not do this on production nor CI, of course.

Bonus: other macro debugging tips

There are several kinds of errors one can have when writing macros:

  • If you are dealing with a complex recursive macro

    or even, just a chain of macro invocations, with a problematic invocation in the middle.

    In that case, I suggest trace_macros! be used:

    • Write trace_macros!(true); before the problematic macro invocation (with an optional trace_macros!(false); after it, to reduce the noise from tracing unrelated macros).
  • If the macro expands to syntactically invalid / rejected-by-the-parser code:

    • trace_macros! can still be useful, although a big expansion will hardly be readable in that format;

    • You can use log_syntax! { … } to enscope the output of the macro:

        macro_rules! my_macro {(
      - ) => (
      + ) => (log_syntax! {
            long output…
      + })}
      - )}
    • Or, if it is a proc-macro, you can simply

      call {e,}println!(…) on the output TokenStream{,2}.

  • The macro expands to semantically invalid code:

    • -Z macro-backtrace

      can indeed be useful here to help you pin-point the problematic code inside the macro definition;

    • Otherwise, a good old expansion of the emitted code will be very welcome. Ideally, this is done through:

      cargo expand

      should it be installed, else:

      # Should use `cargo +nightly`, but if you don't have it installed,
      # you might get away with hackily forcing the nightly mode
      # (don't use in production, only when dev-debugging!)
      cargo rustc --profile=check -- -Z unpretty=expanded

      In both cases replacing the macro invocation with the copy-pasted code may provide better-spanned / detailed error messages :slight_smile:

      • When manually pasting the expanded code, the error disappears

        This means your macro has one of the two following issues:

        • Hygiene: you may be trying to have caller-provided code refer to an internal-to-the-macro / macro-defined variable, or vice versa. This currently only applies to local variables (and, technically, to lifetimes and $crate);

        • Grouping / metavariables. See ::defile's documentation or the last paragraphs of this section from the Rust Reference.


Thanks so much! I did manage to debug my error.

1 Like

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.