dtolnay/cargo-expand

cargo expand in some case deletes nested braces that are syntactically meaningful

Closed this issue · 1 comments

We had a buggy procedural macro that when run on the following enum

enum Data {
    A,
}

would try to create a value by generating the expression Data :: A { {} }, which is syntactically incorrect. The problem is that cargo expand was displaying the same expression as Data :: A {}, we guess because of some simplification procedure which, however, in this case, was transforming a syntactically incorrect sequence of tokens into a correct one. Thus, we were seeing errors in the compiler, but the code returned by cargo expand would compile without problem. Printing manually the output of the macro highlighted the problem above.

A minimized example is as follows: consider the following proc macro:

#[proc_macro_derive(Test)]
pub fn test_derive(input: TokenStream) -> TokenStream {
    let out = quote!{ fn test() { let _ = Data::A {{}}; } }.into();
    eprintln!("out: {}", out);
    out
}

and the source code

#[derive(Test)]
enum Data {
    A,
}

When one invokes cargo expand, the output is of eprintln!is

out: fn test() { let _ = Data :: A { {} } ; }

whereas the output of cargo expand is

enum Data { A, }
fn test() { let _ = Data::A {}; }

and the compiler complains with

error: expected identifier, found `{`
  |
9 | #[derive(Test)]
  |          ^^^^
  |          |
  |          expected identifier
  |          while parsing this struct
  |
  = note: this error originates in the derive macro `Test` (in Nightly builds, run with -Z macro-backtrace for more info)

I don't think this is a cargo-expand issue, since you would get the same output from cargo rustc -- -Zunpretty=expanded which does not involve cargo-expand.