Skip to content

regression 1.49: macro_rules unexpected tokens #79908

New issue

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

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

Already on GitHub? # to your account

Closed
Mark-Simulacrum opened this issue Dec 10, 2020 · 22 comments · Fixed by #80135
Closed

regression 1.49: macro_rules unexpected tokens #79908

Mark-Simulacrum opened this issue Dec 10, 2020 · 22 comments · Fixed by #80135
Assignees
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The lexing & parsing of Rust source code to an AST ICEBreaker-Cleanup-Crew Helping to "clean up" bugs with minimal examples and bisections P-critical Critical priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Milestone

Comments

@Mark-Simulacrum
Copy link
Member

Unclear on the extent to which these are the same problem:

cc @petrochenkov @Aaron1011

@Mark-Simulacrum Mark-Simulacrum added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) regression-from-stable-to-beta Performance or correctness regression from stable to beta. labels Dec 10, 2020
@Mark-Simulacrum Mark-Simulacrum added this to the 1.49.0 milestone Dec 10, 2020
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Dec 10, 2020
@Aaron1011
Copy link
Member

The fourier error looks like an old bug that was fixed by calebzulawski/fourier#17

@Mark-Simulacrum
Copy link
Member Author

https://crates.io/crates/fourier only lists 0.1.0 so we should probably nag @calebzulawski about a point release one more time :)

@calebzulawski
Copy link
Member

Whoops, looks like I half-fixed it. One of my dependencies is too strict. It does look like the same error so probably not a regression...

@Mark-Simulacrum
Copy link
Member Author

cc @petrochenkov

@Mark-Simulacrum Mark-Simulacrum added E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example labels Dec 11, 2020
@camelid camelid added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Dec 11, 2020
@camelid
Copy link
Member

camelid commented Dec 16, 2020

@apiraino and I both feel unclear about this: Is this a Rust regression or a regression in a library that was then picked up by Crater?

@Mark-Simulacrum
Copy link
Member Author

This is a regression in the Rust compiler.

@camelid
Copy link
Member

camelid commented Dec 16, 2020

The tiger error seems to me like fallout from implementing inline_const. I'm guessing the issue is that it's expecting a block but immediately gets a literal. Not sure how this is supposed to behave though.


Reposting the error here:

[INFO] [stdout] error: expected expression, found keyword `const`
[INFO] [stdout]    --> src/ir.rs:481:23
[INFO] [stdout]     |
[INFO] [stdout] 347 |     (exp $e:expr) => {
[INFO] [stdout]     |          ------- while parsing argument for this `expr` macro fragment
[INFO] [stdout] ...
[INFO] [stdout] 481 |             stmt!(exp const 1);
[INFO] [stdout]     |                       ^^^^^ expected expression
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: expected expression, found keyword `const`
[INFO] [stdout]    --> src/ir.rs:482:23
[INFO] [stdout]     |
[INFO] [stdout] 347 |     (exp $e:expr) => {
[INFO] [stdout]     |          ------- while parsing argument for this `expr` macro fragment
[INFO] [stdout] ...
[INFO] [stdout] 482 |             stmt!(exp const 2);
[INFO] [stdout]     |                       ^^^^^ expected expression
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: expected expression, found keyword `const`
[INFO] [stdout]    --> src/ir.rs:483:23
[INFO] [stdout]     |
[INFO] [stdout] 347 |     (exp $e:expr) => {
[INFO] [stdout]     |          ------- while parsing argument for this `expr` macro fragment
[INFO] [stdout] ...
[INFO] [stdout] 483 |             stmt!(exp const 3);
[INFO] [stdout]     |                       ^^^^^ expected expression
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: aborting due to 3 previous errors

@camelid
Copy link
Member

camelid commented Dec 16, 2020

But I'm not quite sure; the span seems potentially wrong.

@spastorino
Copy link
Member

@rustbot ping cleanup

would be nice to get an MCVE

@rustbot rustbot added the ICEBreaker-Cleanup-Crew Helping to "clean up" bugs with minimal examples and bisections label Dec 16, 2020
@rustbot
Copy link
Collaborator

rustbot commented Dec 16, 2020

Hey Cleanup Crew ICE-breakers! This bug has been identified as a good
"Cleanup ICE-breaking candidate". In case it's useful, here are some
instructions for tackling these sorts of bugs. Maybe take a look?
Thanks! <3

cc @AminArria @camelid @chrissimpkins @contrun @DutchGhost @elshize @ethanboxx @h-michael @HallerPatrick @hdhoang @hellow554 @imtsuki @JamesPatrickGill @kanru @KarlK90 @LeSeulArtichaut @MAdrianMattocks @matheus-consoli @mental32 @nmccarty @Noah-Kennedy @pard68 @PeytonT @pierreN @Redblueflame @RobbieClarken @RobertoSnap @robjtede @SarthakSingh31 @shekohex @sinato @smmalis37 @steffahn @Stupremee @tamuhey @turboladen @woshilapin @yerke

@camelid
Copy link
Member

camelid commented Dec 16, 2020

Somewhat minimized (playground):

macro_rules! exp {
    (const $n:expr) => {
        Box::new(Exp::Const($n))
    };
}

macro_rules! stmt {
    (exp $e:expr) => {
        Box::new(Stmt::Exp($e))
    };
    (exp $($t:tt)+) => {
        Box::new(Stmt::Exp(exp!($($t)+)))
    };
}

macro_rules! seq {
    ($stmt1:expr; $stmt2:expr $(;)?) => {
        Box::new(Stmt::Seq($stmt1, $stmt2))
    };
    ($stmt1:expr; $stmt2:expr; $($stmt:expr);+ $(;)?) => {
        seq!(seq!($stmt1; $stmt2); $($stmt);+)
    };
}

fn main() {
    let seq = seq!(
        stmt!(exp const 1);
        stmt!(exp const 2);
        stmt!(exp const 3);
    );
}

On stable, it produces a bunch of semantic errors (which make sense since I removed a lot of type definitions), but on beta it produces:

error: expected expression, found keyword `const`
  --> src/main.rs:99:19
   |
47 |     (exp $e:expr) => {
   |          ------- while parsing argument for this `expr` macro fragment
...
99 |         stmt!(exp const 1);
   |                   ^^^^^ expected expression

error: expected expression, found keyword `const`
   --> src/main.rs:100:19
    |
47  |     (exp $e:expr) => {
    |          ------- while parsing argument for this `expr` macro fragment
...
100 |         stmt!(exp const 2);
    |                   ^^^^^ expected expression

error: expected expression, found keyword `const`
   --> src/main.rs:101:19
    |
47  |     (exp $e:expr) => {
    |          ------- while parsing argument for this `expr` macro fragment
...
101 |         stmt!(exp const 3);
    |                   ^^^^^ expected expression

@spastorino
Copy link
Member

Assigning P-high as discussed as part of the Prioritization Working Group procedure and removing I-prioritize.

@spastorino spastorino added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Dec 16, 2020
@camelid
Copy link
Member

camelid commented Dec 16, 2020

Much more minimized:

macro_rules! exp {
    (const $n:expr) => {
        $n
    };
}

macro_rules! stmt {
    (exp $e:expr) => {
        $e
    };
    (exp $($t:tt)+) => {
        exp!($($t)+)
    };
}

fn main() {
    stmt!(exp const 1);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: expected expression, found keyword `const`
  --> src/main.rs:17:15
   |
8  |     (exp $e:expr) => {
   |          ------- while parsing argument for this `expr` macro fragment
...
17 |     stmt!(exp const 1);
   |               ^^^^^ expected expression

warning: unused macro definition
 --> src/main.rs:1:1
  |
1 | / macro_rules! exp {
2 | |     (const $n:expr) => {
3 | |         $n
4 | |     };
5 | | }
  | |_^
  |
  = note: `#[warn(unused_macros)]` on by default

error: aborting due to previous error; 1 warning emitted

error: could not compile `playground`

To learn more, run the command again with --verbose.

@camelid camelid removed the E-needs-mcve Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable Example label Dec 16, 2020
@camelid
Copy link
Member

camelid commented Dec 16, 2020

Here's the code again:

macro_rules! exp {
    (const $n:expr) => {
        $n
    };
}

macro_rules! stmt {
    (exp $e:expr) => {
        $e
    };
    (exp $($t:tt)+) => {
        exp!($($t)+)
    };
}

fn main() {
    stmt!(exp const 1);
}

I think the issue is that on beta the compiler thinks the const in the macro invocation is starting an expression because of the new inline_const feature – thus it thinks it's using the first rule in the macro. But then when doing macro expansion, it realizes that it's actually not a valid expression because it's missing braces.

On stable this is not an issue because the compiler never thinks that const is starting an expression.

I think the fix might be to not treat const as the start of an expression if it is not immediately followed by braces.


See the original inline_const PR: #77124.

cc @spastorino who has been implementing inline_const

@camelid
Copy link
Member

camelid commented Dec 16, 2020

My bisection is in line with my diagnosis:

searched nightlies: from nightly-2020-10-15 to nightly-2020-10-19
regressed nightly: nightly-2020-10-18
searched commits: from e3051d8 to 043eca7
regressed commit: 6af9846

bisected with cargo-bisect-rustc v0.6.0

Host triple: x86_64-apple-darwin
Reproduce with:

cargo bisect-rustc --preserve --regress=error --start=2020-10-15 --end=2020-10-19 

@camelid camelid removed the E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc label Dec 16, 2020
@camelid camelid self-assigned this Dec 16, 2020
@camelid
Copy link
Member

camelid commented Dec 16, 2020

I'm going to try working on this. If I get stuck I'll release my assignment since this is P-high!

@camelid camelid added the A-parser Area: The lexing & parsing of Rust source code to an AST label Dec 16, 2020
@pnkfelix pnkfelix added P-critical Critical priority and removed P-high High priority labels Dec 17, 2020
@camelid
Copy link
Member

camelid commented Dec 17, 2020

So I'm trying to figure out which code is the culprit here. The inline_const PR is the one that introduced the regression, but looking at its changes I don't know if it's actual the underlying cause. I think the issue might be in the macro expansion code, but I'm not familiar with it at all.

Since this issue is P-critical and potentially a release blocker, I'm going to release my assignment so that someone more experienced can take it over. Though I'm happy to help if there's some way to do that!

@camelid camelid removed their assignment Dec 17, 2020
@camelid
Copy link
Member

camelid commented Dec 17, 2020

Actually, I just noticed that petrochenkov responded to my message asking for help finding the code 😄

@camelid camelid self-assigned this Dec 17, 2020
RalfJung added a commit to RalfJung/rust that referenced this issue Dec 18, 2020
@bors bors closed this as completed in 9269995 Dec 18, 2020
@camelid
Copy link
Member

camelid commented Dec 18, 2020

This should be fixed on the next nightly.

@Mark-Simulacrum
Copy link
Member Author

Reopening to track beta fix.

@Mark-Simulacrum
Copy link
Member Author

Should be backported to beta as part of #80417.

@camelid
Copy link
Member

camelid commented Dec 29, 2020

I think this can be closed as #80417 has been merged?

lf- added a commit to lf-/rust that referenced this issue Apr 26, 2021
This makes it possible to use `inline_const` (rust-lang#76001) and `let_chains`
(rust-lang#53667) inside macros' `expr` patterns in a future edition by
bifurcating the `expr` nonterminal in a similar way to `pat2021` to
remove some backwards compatibility exceptions that disallow
`const`/`let` at the beginning of an `expr` match.

Fixes rust-lang#84155 and relaxes the backward compat restriction from rust-lang#80135 for
a future edition. This is not intended to go into 2021 as it I don't
think it's simple to write an automatic fix, and certainly not now that
it's past the soft deadline for inclusion in 2021 by a long shot.

Here is a pathological case of rust-lang#79908 that forces this to be an edition
change:

```rust
macro_rules! evil {
    ($e:expr) => {
        // or something else
        const {$e-1}
    };
    (const $b:block) => {
        const {$b}
    }
}
fn main() {
    let x = 5;
    match x {
        evil!(const { 5 }) => panic!("oh no"),
        _ => (),
    };
}
```
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The lexing & parsing of Rust source code to an AST ICEBreaker-Cleanup-Crew Helping to "clean up" bugs with minimal examples and bisections P-critical Critical priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants