-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Macro matchers only match when they feel like it #27832
Comments
It seems like the However, fixing this (if it can be fixed) is probably a breaking change :( |
Found the culprit: https://github.com/rust-lang/rust/blob/master/src/libsyntax/ext/tt/macro_parser.rs#L514-L522
Do you really think this would break something? I actually don't think it would, since a fix for this should only accept more macro invocations. |
On second thought... I think that's not the direct cause, since all other fragments behave roughly the same. Oh well, back to the drawing board |
Okay, so as it turns out, all NT parsers introduce this bug (except macro_rules! m {
( $b:expr ) => ();
( $t:tt $u:tt ) => ();
}
fn main() {
m!(3); // works trivially
m!(1 2); // works, since `1` is a valid expression
m!(_ 1); // doesn't work, since `_` is not an expression (but a valid TT, of course)
} Now that this confusion is out of the way, I think I see what happens: When parsing However, when parsing So, fixing this would indeed be a breaking change, since the intended behaviour is (at least as far as I know), to reject the invocation, but this isn't happening. |
@jonas-schievink I disagree that attempting the second arm is a bug. Ideally, Ideally, your last example should go something like this (using
|
That would indeed be useful! But I think this comment implies that that isn't the intended behaviour: rust/src/libsyntax/ext/tt/macro_parser.rs Lines 11 to 13 in c115c51
|
@jonas-schievink I believe that's referring to how it parses within a rule. Earley parsers can deal with ambiguities by tracking multiple potential parse forests (if I remember correctly; my understanding is a little vague). What it's saying is that it has to commit to parsing a non-terminal (i.e. higher-level productions like expressions) because the parser doesn't have any way to back out of a partial parse. So when it encounters one, it has to parse it, come hell or high water. Having the macro system not check successive rules once a rule starts matching would be apocalyptic: it would kill damn near every useful, non-trivial macro. We're talking mass hysteria, cats and dogs living together. |
Fair enough. In that case the bug is just that the macro expander will panic when it can't parse an NT, so it can't backtrack. I also managed to dig up #3232, which was closed as "not a bug", but this definitely feels like one. |
@jonas-schievink Sorry to dig this up again, but isn't an |
@dylanede Correct! That's why I mentioned this comment:
(AFAIK, token == terminal) |
I got bitten by this bug too. Note that I see two different issues here:
|
Fixes rust-lang#24189. Fixes rust-lang#26444. Fixes rust-lang#27832. Fixes rust-lang#34030. Fixes rust-lang#35650. Fixes rust-lang#39964. Fixes the 4th comment in rust-lang#40569. Fixes the issue blocking rust-lang#40984.
…seyfried Only match a fragment specifier the if it starts with certain tokens. When trying to match a fragment specifier, we first predict whether the current token can be matched at all. If it cannot be matched, don't bother to push the Earley item to `bb_eis`. This can fix a lot of issues which otherwise requires full backtracking (#42838). In this PR the prediction treatment is not done for `:item`, `:stmt` and `:tt`, but it could be expanded in the future. Fixes #24189. Fixes #26444. Fixes #27832. Fixes #34030. Fixes #35650. Fixes #39964. Fixes the 4th comment in #40569. Fixes the issue blocking #40984.
...or at least that's how much I currently understand, since macros are really counterintuitive sometimes.
I don't think this is supposed to happen. Even if it is, the exact rules used for macro matching should definitely be documented somewhere (I think there's not even an RFC).
The text was updated successfully, but these errors were encountered: