Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reformatting inside of a proc macro call site can change program behavior #3434

Closed
chinedufn opened this issue Mar 7, 2019 · 9 comments
Closed
Labels
bug Panic, non-idempotency, invalid code, etc. feature-request

Comments

@chinedufn
Copy link

chinedufn commented Mar 7, 2019

Background

I have a procedural macro that parses html.

It looks like rustfmt will format the tokens inside of my macro

For example:

html! { <div>
Hello
</div>}

The word Hello will get moved to the right a bit if I run rustfmt.

Problem

This is a problem because I'm using Spans to generate different code based on the locations of different tokens. So running rustfmt changes how the final program behaves.

Potential Solution

Don't reformat the tokens inside of a procedural macro call site by default since it can change the behavior of a program


No idea how difficult or easy any of this is so just trying to detail my experience here. Happy to answer any questions or provide any missing context!

@topecongiro
Copy link
Contributor

Hmm, so are you using rustfmt as a library inside your procedural macro? I am not entirely clear how rustfmt affects your use case.

@chinedufn
Copy link
Author

chinedufn commented Mar 7, 2019

No not that - sorry for being unclear!


So let's say I have this program that uses my procedural macro

fn main () {
  let before_rustfmt = my_macro! { <div>
Hello</div>
  }.to_string();
}

Now let's say I run rustfmt on my program and it gets reformatted to something like this:

fn main () {
  let after_rustfmt = my_macro! { <div>
      Hello</div>
  }.to_string();
}

Notice that hello has been moved.

If my_macro is looking at the Span's in order to determine what code to generate, we now have two completely different programs.

For example. Example one might generate this:

<div>\nHello</div> <--- before rustfmt

While example two might generate

<div>\n    Hello</div> //  <--- after rustfmt

So, in short, if rustfmt is run on a program that uses some procedural macros, and the procedural macro that it uses is looking at Span's, rustfmt can change the behavior of the final compiled program.


Let me know if I failed to communicate the problem!

@topecongiro
Copy link
Contributor

Thank you for your clarification. rustfmt cannot distinguish between normal macro and procedural macro calls, so skipping procedural macro only seems hard to solve.

One way is to extend rustfmt::skip to take identifiers as arguments, and skip formatting all macro calls whose name match the identifier passed to rustfmt::skip. E.g., we may want something like the following:

// Skip formatting everything whose name is `html`
#![rustfmt::skip(html)]
// Or make it explicit that you only want to skip macro calls
#![rustfmt::skip::macro(html)]

@chinedufn
Copy link
Author

Thanks you for the visual example!

I really like #![rustfmt::skip::macro(html)] - that would work perfectly!

How complex would that be implementation wise?

@topecongiro topecongiro added bug Panic, non-idempotency, invalid code, etc. a-comments feature-request and removed a-comments labels Mar 8, 2019
@topecongiro
Copy link
Contributor

I don't think implementing this takes that much time, should be a nice weekend project :)

@Emerentius
Copy link

I see that a PR implementing the skip functionality has been merged, so is this fixed?
Can rustfmt::skip::macros be used by the macro author so it'll automatically apply to all consumers or will everyone have to do it (and learn how to do it!) themselves?

@scampi
Copy link
Contributor

scampi commented Apr 14, 2019

yes this is fixed, sorry the issue got left behind opened

@scampi scampi closed this as completed Apr 14, 2019
@topecongiro
Copy link
Contributor

Can rustfmt::skip::macros be used by the macro author so it'll automatically apply to all consumers or will everyone have to do it (and learn how to do it!) themselves?

No, rustfmt does not perform name resolution, so the information from a macro definition is not visible to rustfmt.

@alun
Copy link

alun commented Jul 25, 2020

skip looks to be default behaviour now, I'm running 1.4.14-stable. I'd like to try the opposite. Is there a way to enable formatting within html! macro invocation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Panic, non-idempotency, invalid code, etc. feature-request
Projects
None yet
Development

No branches or pull requests

5 participants