Skip to content

Commit bceaba8

Browse files
committed
rollback gating for failing macro matchers
1 parent fe95cd2 commit bceaba8

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

src/libsyntax/feature_gate/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ pub fn check_crate(krate: &ast::Crate,
883883
// FIXME(eddyb) do something more useful than always
884884
// disabling these uses of early feature-gatings.
885885
if false {
886-
for span in &*parse_sess.gated_spans.$gate.borrow() {
886+
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
887887
gate_feature!(&visitor, $gate, *span, $msg);
888888
}
889889
}

src/libsyntax/sess.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use std::str;
1919
/// Collected spans during parsing for places where a certain feature was
2020
/// used and should be feature gated accordingly in `check_crate`.
2121
#[derive(Default)]
22-
crate struct GatedSpans {
23-
crate spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
22+
pub struct GatedSpans {
23+
pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
2424
}
2525

2626
impl GatedSpans {
@@ -57,6 +57,15 @@ impl GatedSpans {
5757
.get(&feature)
5858
.map_or(true, |spans| spans.is_empty())
5959
}
60+
61+
/// Prepend the given set of `spans` onto the set in `self`.
62+
pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
63+
let mut inner = self.spans.borrow_mut();
64+
for (gate, mut gate_spans) in inner.drain() {
65+
spans.entry(gate).or_default().append(&mut gate_spans);
66+
}
67+
*inner = spans;
68+
}
6069
}
6170

6271
/// Info about a parsing session.
@@ -77,7 +86,7 @@ pub struct ParseSess {
7786
/// analysis.
7887
pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
7988
pub injected_crate_name: Once<Symbol>,
80-
crate gated_spans: GatedSpans,
89+
pub gated_spans: GatedSpans,
8190
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
8291
pub reached_eof: Lock<bool>,
8392
}

src/libsyntax_expand/mbe/macro_rules.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use syntax_pos::Span;
2929
use rustc_data_structures::fx::FxHashMap;
3030
use std::borrow::Cow;
3131
use std::collections::hash_map::Entry;
32-
use std::slice;
32+
use std::{mem, slice};
3333

3434
use errors::Applicability;
3535
use rustc_data_structures::sync::Lrc;
@@ -182,16 +182,25 @@ fn generic_extension<'cx>(
182182

183183
// Which arm's failure should we report? (the one furthest along)
184184
let mut best_failure: Option<(Token, &str)> = None;
185-
186185
for (i, lhs) in lhses.iter().enumerate() {
187186
// try each arm's matchers
188187
let lhs_tt = match *lhs {
189188
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
190189
_ => cx.span_bug(sp, "malformed macro lhs"),
191190
};
192191

192+
// Take a snapshot of the state of pre-expansion gating at this point.
193+
// This is used so that if a matcher is not `Success(..)`ful,
194+
// then the spans which became gated when parsing the unsucessful matcher
195+
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
196+
let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut());
197+
193198
match parse_tt(cx, lhs_tt, arg.clone()) {
194199
Success(named_matches) => {
200+
// The matcher was `Success(..)`ful.
201+
// Merge the gated spans from parsing the matcher with the pre-existing ones.
202+
cx.parse_sess.gated_spans.merge(gated_spans_snaphot);
203+
195204
let rhs = match rhses[i] {
196205
// ignore delimiters
197206
mbe::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
@@ -248,6 +257,10 @@ fn generic_extension<'cx>(
248257
},
249258
Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]),
250259
}
260+
261+
// The matcher was not `Success(..)`ful.
262+
// Restore to the state before snapshotting and maybe try again.
263+
mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut());
251264
}
252265

253266
let (token, label) = best_failure.expect("ran no matchers");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-pass
2+
3+
// Test that failing macro matchers will not cause pre-expansion errors
4+
// even though they use a feature that is pre-expansion gated.
5+
6+
macro_rules! m {
7+
($e:expr) => { 0 }; // This fails on the input below due to `, foo`.
8+
($e:expr,) => { 1 }; // This also fails to match due to `foo`.
9+
(box $e:expr, foo) => { 2 }; // Successful matcher, we should get `2`.
10+
}
11+
12+
fn main() {
13+
assert_eq!(2, m!(box 42, foo));
14+
}

0 commit comments

Comments
 (0)