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

Crater run for PR #72388 - Recursively expand TokenKind::Interpolated in probably_equal_for_proc_macro #72622

Closed
Aaron1011 opened this issue May 26, 2020 · 22 comments
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Comments

@Aaron1011
Copy link
Member

Better late than never...

@Aaron1011
Copy link
Member Author

@craterbot run start=master#52b605c8cb2f730e607de0777a694cd1b9bb3e15 end=master#7726070fa755f660b5da3f82f46e07d9c6866f69 mode=check-only

@craterbot
Copy link
Collaborator

👌 Experiment pr-72622 created and queued.
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🚧 Experiment pr-72622 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added the S-waiting-on-crater Status: Waiting on a crater run to be completed. label May 26, 2020
@craterbot
Copy link
Collaborator

🎉 Experiment pr-72622 is completed!
📊 709 regressed and 2 fixed (106133 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels May 28, 2020
@Aaron1011
Copy link
Member Author

root: async-graphql - 4 (0 gh, 4 crates.io) detected crates which regressed due to this; cc @sunli829

  • async-graphql-1.13.2: start v. end
  • async-graphql-actix-web-1.13.2: start v. end
  • async-graphql-tide-1.13.2: start v. end
  • async-graphql-warp-1.13.2: start v. end

root: ckb-fixed-hash-hack - 2 (2 gh, 0 crates.io) detected crates which regressed due to thisno owner?

root: dwm-status - 2 (1 gh, 1 crates.io) detected crates which regressed due to this; cc @Gerschtli

root: fourier - 2 (1 gh, 1 crates.io) detected crates which regressed due to this; cc @calebzulawski

root: frame-support - 16 (8 gh, 8 crates.io) detected crates which regressed due to this; cc @gnunicorn

  • orml-prices-0.1.0: start v. end
  • orml-traits-0.0.1: start v. end
  • pallet-benchmark-2.0.0-rc2: start v. end
  • pallet-evm-2.0.0-rc2: start v. end
  • pallet-im-online-2.0.0-rc2: start v. end
  • pallet-mandate-2.0.3: start v. end
  • substrate-frame-rpc-support-2.0.0-rc2: start v. end
  • sunshine-util-0.0.2: start v. end
  • ETeissonniere/pallet-mandate: start v. end
  • TovarishFin/tovar-pallet: start v. end
  • bifrost-codes/substrate-rpc-client: start v. end
  • bitrocks/secret-social-recovery: start v. end
  • gautamdhameja/substrate-account-set: start v. end
  • hsputra/test-palette: start v. end
  • substrate-developer-hub/pallet-did: start v. end
  • substrate-developer-hub/substrate-pallet-template: start v. end

root: js-sys - 468 (293 gh, 175 crates.io) detected crates which regressed due to this; cc @alexcrichton, @fitzgen

root: reproto-core - 8 (0 gh, 8 crates.io) detected crates which regressed due to this; cc @udoprog

  • root: screeps-api: 1 dependents end v. start; cc @daboross
  • root: serde-tcod-config-parser: 1 dependents end v. start; cc @alexschrod

root: srml-support - 6 (6 gh, 0 crates.io) detected crates which regressed due to thisno owner?

  • Joystream/substrate-forum-module: start v. end
  • Ramshreyas/identity: start v. end
  • projectmeka/meka-identity: start v. end
  • shawntabrizi/substrate-module-template: start v. end
  • shawntabrizi/substrate-price-oracle: start v. end
  • shawntabrizi/substrate-runtime-benchmarking: start v. end

root: time-macros-impl - 176 (119 gh, 57 crates.io) detected crates which regressed due to this; cc @jhpratt

root: vek - 5 (3 gh, 2 crates.io) detected crates which regressed due to this; cc @yoanlcq

root: wirefilter-engine - 2 (1 gh, 1 crates.io) detected crates which regressed due to this; cc @RReverser

root: unknown causes - 2 (1 gh, 1 crates.io) detected crates which regressed due to thisno owner?

@jhpratt
Copy link
Member

jhpratt commented May 29, 2020

As the maintainer of the time crate, what should I do, if anything? It's one of the largest regressions.

I've already received confirmation that running cargo update -p proc-macro-hack resolves the issue, so I don't think a new release is necessary — the user would still have to update to get the fix.

Realistically I don't even need this specific use, as it only saves me a little bit of code. But at the same time, I don't think removing the proc macro inside of the macro_rules will make anything better.

@wez
Copy link

wez commented May 29, 2020

I'm not sure why I've been mentioned here; what am I missing?

@dagit
Copy link

dagit commented May 29, 2020

Same. I think it's some sort of spam bot or error. Definitely unwelcome and annoying.

@Aaron1011
Copy link
Member Author

Aaron1011 commented May 29, 2020

@wez @dagit: I'm really sorry - the tool I used to generate the report automatically included mentions. I should have removed them before posting the report.

EDIT: I failed to read the documentation for crater-generate-report - I thought that the option to generate pings was actually an option to control which crates were considered.

@Aaron1011
Copy link
Member Author

The fallout from this change is extensive - I started trying to fix async-graphql, but there appears to be several layers of issues (the async-graphql-derive crate needs to handle syn::Type::Group, but it's also emitting a #[async_trait] invocation that has the wrong SyntaxContext for a self token due to a reparse).

I think we should revert the original PR, and work on submitting PRs to the regressed crates.

@Aaron1011
Copy link
Member Author

I've started triaging the regressed crates here: https://hackmd.io/ItrXWRaSSquVwoJATPx3PQ

@daboross
Copy link
Contributor

daboross commented May 29, 2020

I was trying to fix this in screeps-api, but I really can't figure out what's wrong with the code. Is this an unintended regression, or could you point out what I've done wrong here, or is this serde_derive's problem somehow?

macro_rules! regurgitate_struct_def {
    (
        $( #[$struct_attr:meta] )*
        $item_vis:vis struct $name:ident {
            $(
                $( #[$field_attr:meta] )*
                $field_vis:vis $field:ident : $type:ty,
            )*
        }
    ) => (
        $( #[$struct_attr] )*
        $item_vis struct $name {
            $(
                $( #[$field_attr] )*
                $field_vis $field: $type,
            )*
        }
    )
}

regurgitate_struct_def! {
    #[derive(serde_derive::Deserialize)]
    pub struct Foo {
        _phantom: (),
    }
}

For reference, it errors with

error: expected identifier
  --> src/lib.rs:15:17
   |
15 |                   $field_vis $field: $type,
   |                   ^^^^^^^^^^
...
21 | / regurgitate_struct_def! {
22 | |     #[derive(serde_derive::Deserialize)]
23 | |     pub struct Foo {
24 | |         _phantom: (),
25 | |     }
26 | | }
   | |_- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

error: could not compile `nightlytest`.

According to the rust reference, vis metavariables are allowed to be empty, so I would fully expect this to work.

Edit: I looked at the link for the proper way to fix this from the hackmd, but it seems to be entirely about proc macros. Does this mean it is serde_derive's problem and as long as they fix it I should be good to go?

@CasualX
Copy link

CasualX commented May 29, 2020

Hi, I'd love to fix any 'broken' code on my end but I'm unsure what's going on here. What exactly is this issue trying to do?

I have the impression it's the proc macro hack workaround that is problematic but I'm not sure why? All I do is use a macro rules macro to expand to a #[attribute] const NAME: Type = VALUE; VALUE. Then the proc macro can produce the value via the attribute proc macro. There doesn't appear to be a fundamental problem with this.

Also proc macros expanding to statements and expressions when? :)

@jhpratt
Copy link
Member

jhpratt commented May 29, 2020

@CasualX Have you tried updating the version of proc macro hack? That's all that was necessary for the time crate.

And proc macros will be able to expand to expressions in 1.45, which is due to be released July 16!

@CasualX
Copy link

CasualX commented May 29, 2020

@jhpratt I don't use proc macro hack because it depends on syn and quote which takes forever to compile. I learned how proc macro hack worked and implemented the bare essentials myself. I'm not a fan of unnecessary and slow to compile dependencies.

@dtolnay
Copy link
Member

dtolnay commented May 29, 2020

@CasualX fwiw proc-macro-hack does not depend on syn. It has no dependencies. It has dev-dependencies for compiling its test suite but downstream code does not build those.

kornelski added a commit to crev-dev/cargo-crev that referenced this issue May 29, 2020
rust-lang/rust#72622

also removes unused deps
@leo60228
Copy link
Contributor

Wait, what? I don't think I've ever used the name testing for a proc macro, much less published it...

@leo60228
Copy link
Contributor

Yeah, the testing crate isn't mine and isn't even a proc macro.

@leo60228
Copy link
Contributor

Oh, it's this repo I made to help someone on Discord: https://github.com/leo60228/axiom-demo
That's not a proc macro, though. No idea why it's a root.

JohnTitor added a commit to JohnTitor/rust that referenced this issue May 30, 2020
…, r=petrochenkov

Revert recursive `TokenKind::Interpolated` expansion for now

The crater run rust-lang#72622 revealed many root regressions, at least one of which is going to take some time to fix.

For now, let's revert rust-lang#72388 to allow the 709 affected crates to continue building on the latest nightly.
yvt added a commit to yvt/try_match-rs that referenced this issue May 30, 2020
Tested with:
- nightly-2020-05-30
- nightly-2020-04-30
- 1.40.0
- 1.37.0

This commit fixes non-trivial patterns causing an error saying
"unexpected token". This is done by parenthesizing `$p`. This might have
something to do with an input pattern being wrapped by a
`None`-delimited group and I suspect this might have been overlooked by
the crater run <rust-lang/rust#72622>, but I'm
not sure.

This commit also implements a work-around for the issue
<dtolnay/proc-macro-hack#46> by capturing
the input expression by `$($in:tt)*`. The first work-around might have
revealed this issue.
Aaron1011 added a commit to Aaron1011/parity-scale-codec that referenced this issue May 30, 2020
Normally, the span of a field has the same hygiene context as
`Span::call_site`. However, it's possible for a struct definition
to be 'constructed' via a `macro_rules` macro such that the field
has a different hygiene context. This will cause the expanded code
to be unable to resolve any references to `self`, resulting in a
compilation error.

This pull request uses `quote!` instead of `quote_spanned!` when
emitting a 'self' identifier. `quote_spanned!` is still used for
everything else in the emitted method, meaning that error messages
will still point to the proper field.

I've included a test case which triggers this issue on
Rust 1.43.1. It's current difficult to hit this issue
other than in this artificial case, but that will change
once rust-lang/rust#72622 is re-landed.
bkchr pushed a commit to paritytech/parity-scale-codec that referenced this issue May 30, 2020
Normally, the span of a field has the same hygiene context as
`Span::call_site`. However, it's possible for a struct definition
to be 'constructed' via a `macro_rules` macro such that the field
has a different hygiene context. This will cause the expanded code
to be unable to resolve any references to `self`, resulting in a
compilation error.

This pull request uses `quote!` instead of `quote_spanned!` when
emitting a 'self' identifier. `quote_spanned!` is still used for
everything else in the emitted method, meaning that error messages
will still point to the proper field.

I've included a test case which triggers this issue on
Rust 1.43.1. It's current difficult to hit this issue
other than in this artificial case, but that will change
once rust-lang/rust#72622 is re-landed.
@Aaron1011
Copy link
Member Author

Aaron1011 commented May 31, 2020

One of the failing crates has this concerning code:

#[macro_export]
macro_rules! slider {
    ( $name:expr, $min:expr, $max:expr, $value:expr ) => {
        html!(<Slider name=$name min=$min max=$max value=&mut $value as *mut Value value_changed=value_changed.clone() />)
    };
}

it's invoked like this:

impl ScaledHead {
    pub fn controls(&mut self, value_changed: Callback<()>) -> Html {
        html!(
            <>
                <Group name="Grid">
                    {crate::slider!("Size", 8.0, 32.0, self.scale)}
                </Group>
                {self.head.controls(value_changed.clone())}
            </>
        )
    }

This is a macro_rules macro that effectively has call-site hygiene for local variables. The value_changed reference is resolved in the scope of the caller (in the example invocation, to the function parameter value_changed: Callback<()>. Note that this identifier is not passed into slider.

Prior to PR #72388, we were losing span information when html! (a proc-macro) was invoked by slider. As a result, all of the expanded tokens ended up with SyntaxContext::root, allowing unhygienic access to local variables.

When #72388 landed, we started retaining proper Spans, leading us to correctly fail to resolve value_changed in the context of the slider expansion.

It looks as though slider was written this way deliberately - the author may not have realized that this behavior was a bug.

What is the policy for rolling out this kind of change? I'll send a PR to fix the slider macro, but I'm concerned that some crates might have more complex macros that are relying on this bug.

cc @petrochenkov @dtolnay.

Aaron1011 added a commit to Aaron1011/utils that referenced this issue May 31, 2020
Currently, rustc does not pass the exact original `TokenStream` to
proc-macros in several cases. This has many undesirable effects, such as
losing correct location information in error message.
See rust-lang/rust#43081 for more details

In the future, rustc will begin passing the correct `TokenStream` to
proc-macros. As a result, some tokens may be wrapped in a
`TokenTree::Group` with `Delimiter::None` (when the tokens originally
came from a `macro_rules!`) macro expansion.

I've determined that this change will cause your crate to stop working
on some inputs. This PR updates `hex-literal-impl` to be compatible with both the
old and new `TokenStream` contents.

If you have any questions, feel free to ask me. See rust-lang/rust#72622 for more details
Aaron1011 added a commit to Aaron1011/oauth1-request-rs that referenced this issue May 31, 2020
Currently, rustc does not pass the exact original TokenStream to
proc-macros in several cases. This has many undesirable effects, such as
losing correct location information in error message.
See rust-lang/rust#43081 for more details

In the future, rustc will begin passing the correct TokenStream to
proc-macros. As a result, `syn` may wrap a type in one or more
`syn::Type::Group`s (if the proc-macro input came from a `macro_rules!` expansion).

I've determined that this can cause `oauth1-request-derive` to fail to match
a `Type::Path`. This PR should properly handle nested groups, allowing
your crate to work with both old and new input.

If you have any questions, feel free to ask me. See rust-lang/rust#72622
for more details.
@Aaron1011
Copy link
Member Author

I've found another unhygenic macro_rules! in serde-tcod-config-parser

    macro_rules! visit_number {
        ($l: expr, $to: ident, $ty: ident) => {
            if $l.token == Token::$to {
                paste::expr! {
                    let result = $l.slice().parse().unwrap();
                    $l.advance();
                    visitor.[<visit_$ty>](result)
                }
            } else {
                unexpected_token!($l, "<number>")
            }
        };
    }

here, visitor ends up getting resolved in the callsite, even though it should have def-site resolution.

Aaron1011 added a commit to Aaron1011/serde-tcod-config-parser that referenced this issue May 31, 2020
In Rust, variable identifiers in a `macro_rules!` body are resolved
in the scope of tht body - they cannot see through to the caller's body.
For example, the following code errors:

```rust
macro_rules! weird_ident {
    () => { my_ident; }
}

fn main() {
    let my_ident = 1;
    weird_ident!();
}
```

However, due to a compiler bug (rust-lang/rust#43081),
this kind of code current compiles when a procedural macro is invoked by
a `macro_rules!` macro. Eventually, this will cause a compilation error.

In the `visit_number!` macro, you're currently writing an expression
involving `visitor`, and passing it to a procedural macro (`paste!`).
However, `visitor` comes from the body of the caller of `visit_number!`,
so this code will stop compiling once the compiler bug is fixed.

Fortunately, the identifier of `visitor` can be passed into
`visit_number!`. This modified code will with the current version of
Rust, as well as future version that causes the old code into an error.

Feel free to ask me about any questions you may have. For more details,
see rust-lang/rust#72622
Aaron1011 added a commit to Aaron1011/yaserde that referenced this issue May 31, 2020
Currently, rustc does not pass the exact original TokenStream to
proc-macros in several cases. This has many undesirable effects, such as
losing correct location information in error message.
See rust-lang/rust#43081 for more details

In the future, rustc will begin passing the correct TokenStream to
proc-macros. As a result, `syn` may wrap a type in one or more
`syn::Type::Group`s (if the proc-macro input came from a `macro_rules!` expansion).

I've determined that this can cause `yaserde-derive` to fail to match
a `Type::Path`. This PR should properly handle nested groups, allowing
your crate to work with both old and new input.

If you have any questions, feel free to ask me. See rust-lang/rust#72622
for more details.
Aaron1011 added a commit to Aaron1011/oauth1-request-rs that referenced this issue May 31, 2020
Currently, rustc does not pass the exact original TokenStream to
proc-macros in several cases. This has many undesirable effects, such as
losing correct location information in error message.
See rust-lang/rust#43081 for more details

In the future, rustc will begin passing the correct TokenStream to
proc-macros. As a result, `syn` may wrap a type in one or more
`syn::Type::Group`s (if the proc-macro input came from a `macro_rules!` expansion).

I've determined that this can cause `oauth1-request-derive` to fail to match
a `Type::Path`. This PR should properly handle nested groups, allowing
your crate to work with both old and new input.

If you have any questions, feel free to ask me. See rust-lang/rust#72622
for more details.
Aaron1011 added a commit to Aaron1011/oauth1-request-rs that referenced this issue May 31, 2020
Currently, rustc does not pass the exact original TokenStream to
proc-macros in several cases. This has many undesirable effects, such as
losing correct location information in error message.
See rust-lang/rust#43081 for more details

In the future, rustc will begin passing the correct TokenStream to
proc-macros. As a result, `syn` may wrap a type in one or more
`syn::Type::Group`s (if the proc-macro input came from a `macro_rules!` expansion).

I've determined that this can cause `oauth1-request-derive` to fail to match
a `Type::Path`. This PR should properly handle nested groups, allowing
your crate to work with both old and new input.

If you have any questions, feel free to ask me. See rust-lang/rust#72622
for more details.
Aaron1011 added a commit to Aaron1011/face-generator that referenced this issue May 31, 2020
In Rust, variable identifiers in a `macro_rules!` body are resolved
in the scope of tht body - they cannot see through to the caller's body.
For example, the following code errors:

`rust
macro_rules! weird_ident {
    () => { my_ident; }
}

fn main() {
    let my_ident = 1;
    weird_ident!();
}
`

However, due to a compiler bug (rust-lang/rust#43081),
this kind of code current compiles when a procedural macro is invoked by
a `macro_rules!` macro. Eventually, this will cause a compilation error.

In the `color!` and `slider!` macro, you're currently writing an expression
involving `value_changed`, and passing it to a procedural macro (`html!`).
However, `value_changed` comes from the body of the caller of `color!`/`slider!`,
so this code will stop compiling once the compiler bug is fixed.

Fortunately, the identifier of `value_changed` can be passed into
`color!` and `slider!`. This modified code will with the current version of
Rust, as well as future version that causes the old code into an error.

I also ran `cargo update` to bump the dependencies in your Cargo.lock.
This will allow your crate to continue to compile when the compiler bug is fixed,
as you are depending on some crates (e.g. `syn`) that have released updates
to address the issue.

Feel free to ask me about any questions you may have. For more details,
see rust-lang/rust#72622
newpavlov pushed a commit to RustCrypto/utils that referenced this issue Jun 1, 2020
Currently, rustc does not pass the exact original `TokenStream` to
proc-macros in several cases. This has many undesirable effects, such as
losing correct location information in error message.
See rust-lang/rust#43081 for more details

In the future, rustc will begin passing the correct `TokenStream` to
proc-macros. As a result, some tokens may be wrapped in a
`TokenTree::Group` with `Delimiter::None` (when the tokens originally
came from a `macro_rules!`) macro expansion.

I've determined that this change will cause your crate to stop working
on some inputs. This PR updates `hex-literal-impl` to be compatible with both the
old and new `TokenStream` contents.

If you have any questions, feel free to ask me. See rust-lang/rust#72622 for more details
bkchr pushed a commit to paritytech/parity-scale-codec that referenced this issue Jul 28, 2020
Normally, the span of a field has the same hygiene context as
`Span::call_site`. However, it's possible for a struct definition
to be 'constructed' via a `macro_rules` macro such that the field
has a different hygiene context. This will cause the expanded code
to be unable to resolve any references to `self`, resulting in a
compilation error.

This pull request uses `quote!` instead of `quote_spanned!` when
emitting a 'self' identifier. `quote_spanned!` is still used for
everything else in the emitted method, meaning that error messages
will still point to the proper field.

I've included a test case which triggers this issue on
Rust 1.43.1. It's current difficult to hit this issue
other than in this artificial case, but that will change
once rust-lang/rust#72622 is re-landed.
@petrochenkov
Copy link
Contributor

Closing in favor of #73084.

bors added a commit to rust-lang-ci/rust that referenced this issue Aug 23, 2020
…d, r=petrochenkov

Re-land PR rust-lang#72388:  Recursively expand `TokenKind::Interpolated` in `probably_equal_for_proc_macro`

PR rust-lang#72388 allowed us to preserve the original `TokenStream` in more cases during proc-macro expansion, but had to be reverted due to a large number of regressions (See rust-lang#72545 and rust-lang#72622). These regressions fell into two categories

1. Missing handling for `Group`s with `Delimiter::None`, which are inserted during `macro_rules!` expansion (but are lost during stringification and re-parsing). A large number of these regressions were due to `syn` and `proc-macro-hack`, but several crates needed changes to their own proc-macro code.
2. Legitimate hygiene issues that were previously being masked by stringification. Some of these were relatively benign (e.g. [a compiliation error](paritytech/parity-scale-codec#210) caused by misusing `quote_spanned!`). However, two crates had intentionally written unhygenic `macro_rules!` macros, which were able to access identifiers that were not passed as arguments (see rust-lang#72622 (comment)).

All but one of the Crater regressions have now been fixed upstream (see https://hackmd.io/ItrXWRaSSquVwoJATPx3PQ?both). The remaining crate (which has a PR pending at sammhicks/face-generator#1) is not on `crates.io`, and is a Yew application that seems unlikely to have any reverse dependencies.

As @petrochenkov mentioned in rust-lang#72545 (comment), not re-landing PR rust-lang#72388 allows more crates to write unhygenic `macro_rules!` macros, which will eventually stop compiling. Since there is only one Crater regression remaining, since additional crates could write unhygenic `macro_rules!` macros in the time it takes that PR to be merged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

No branches or pull requests

10 participants