about summary refs log tree commit diff
path: root/src/libsyntax_expand
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-11-07 08:51:57 +0100
committerGitHub <noreply@github.com>2019-11-07 08:51:57 +0100
commite19cb40fda70ea3f75bc1927c114ea53d231b288 (patch)
treecf0891bcc1fca581981d14c7ae6c550fc20f26da /src/libsyntax_expand
parent883fe10da2f0651540fd5824898b7d7476969c41 (diff)
parentbceaba86b92325f807351426bfd93ba0513225a4 (diff)
downloadrust-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.rs17
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");