diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-11-07 08:51:57 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-11-07 08:51:57 +0100 |
| commit | e19cb40fda70ea3f75bc1927c114ea53d231b288 (patch) | |
| tree | cf0891bcc1fca581981d14c7ae6c550fc20f26da /src/libsyntax_expand | |
| parent | 883fe10da2f0651540fd5824898b7d7476969c41 (diff) | |
| parent | bceaba86b92325f807351426bfd93ba0513225a4 (diff) | |
| download | rust-e19cb40fda70ea3f75bc1927c114ea53d231b288.tar.gz rust-e19cb40fda70ea3f75bc1927c114ea53d231b288.zip | |
Rollup merge of #65974 - Centril:matcher-friendly-gating, r=petrochenkov
A scheme for more macro-matcher friendly pre-expansion gating
Pre-expansion gating will now avoid gating macro matchers that did not result in `Success(...)`. That is, the following is now OK despite `box 42` being a valid `expr` and that form being pre-expansion gated:
```rust
macro_rules! m {
($e:expr) => { 0 }; // This fails on the input below due to `, foo`.
(box $e:expr, foo) => { 1 }; // Successful matcher, we should get `2`.
}
fn main() {
assert_eq!(1, m!(box 42, foo));
}
```
Closes https://github.com/rust-lang/rust/issues/65846.
r? @petrochenkov
cc @Mark-Simulacrum
Diffstat (limited to 'src/libsyntax_expand')
| -rw-r--r-- | src/libsyntax_expand/mbe/macro_rules.rs | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs index 7a772b0d31d..55719907403 100644 --- a/src/libsyntax_expand/mbe/macro_rules.rs +++ b/src/libsyntax_expand/mbe/macro_rules.rs @@ -29,7 +29,7 @@ use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; use std::borrow::Cow; use std::collections::hash_map::Entry; -use std::slice; +use std::{mem, slice}; use errors::Applicability; use rustc_data_structures::sync::Lrc; @@ -182,7 +182,6 @@ fn generic_extension<'cx>( // Which arm's failure should we report? (the one furthest along) let mut best_failure: Option<(Token, &str)> = None; - for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers let lhs_tt = match *lhs { @@ -190,8 +189,18 @@ fn generic_extension<'cx>( _ => cx.span_bug(sp, "malformed macro lhs"), }; + // Take a snapshot of the state of pre-expansion gating at this point. + // This is used so that if a matcher is not `Success(..)`ful, + // then the spans which became gated when parsing the unsucessful matcher + // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. + let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut()); + match parse_tt(cx, lhs_tt, arg.clone()) { Success(named_matches) => { + // The matcher was `Success(..)`ful. + // Merge the gated spans from parsing the matcher with the pre-existing ones. + cx.parse_sess.gated_spans.merge(gated_spans_snaphot); + let rhs = match rhses[i] { // ignore delimiters mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(), @@ -248,6 +257,10 @@ fn generic_extension<'cx>( }, Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]), } + + // The matcher was not `Success(..)`ful. + // Restore to the state before snapshotting and maybe try again. + mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut()); } let (token, label) = best_failure.expect("ran no matchers"); |
