From fe95cd2f4b3a722e023dc7bba8ff65136be441ca Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 30 Oct 2019 16:38:16 +0100 Subject: revamp pre-expansion gating infra --- src/libsyntax/feature_gate/check.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libsyntax/feature_gate') diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d9cc5f6c169..ea9946a8b7a 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -862,18 +862,17 @@ pub fn check_crate(krate: &ast::Crate, maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable); let mut visitor = PostExpansionVisitor { parse_sess, features }; + let spans = parse_sess.gated_spans.spans.borrow(); macro_rules! gate_all { - ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; - ($spans:ident, $gate:ident, $msg:literal) => { - for span in &*parse_sess.gated_spans.$spans.borrow() { + ($gate:ident, $msg:literal) => { + for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { gate_feature!(&visitor, $gate, *span, $msg); } } } - gate_all!(let_chains, "`let` expressions in this position are experimental"); gate_all!(async_closure, "async closures are unstable"); - gate_all!(yields, generators, "yield syntax is experimental"); + gate_all!(generators, "yield syntax is experimental"); gate_all!(or_patterns, "or-patterns syntax is experimental"); gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); @@ -901,7 +900,6 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(try_blocks, "`try` blocks are unstable"); gate_all!(label_break_value, "labels on blocks are unstable"); gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); - // To avoid noise about type ascription in common syntax errors, // only emit if it is the *only* error. (Also check it last.) if parse_sess.span_diagnostic.err_count() == 0 { -- cgit 1.4.1-3-g733a5 From bceaba86b92325f807351426bfd93ba0513225a4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 30 Oct 2019 17:34:00 +0100 Subject: rollback gating for failing macro matchers --- src/libsyntax/feature_gate/check.rs | 2 +- src/libsyntax/sess.rs | 15 ++++++++++++--- src/libsyntax_expand/mbe/macro_rules.rs | 17 +++++++++++++++-- .../issue-65846-rollback-gating-failing-matcher.rs | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs (limited to 'src/libsyntax/feature_gate') diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index ea9946a8b7a..74a92669a4d 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -883,7 +883,7 @@ pub fn check_crate(krate: &ast::Crate, // FIXME(eddyb) do something more useful than always // disabling these uses of early feature-gatings. if false { - for span in &*parse_sess.gated_spans.$gate.borrow() { + for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { gate_feature!(&visitor, $gate, *span, $msg); } } diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index f677d544bc3..faad3e4af1e 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -19,8 +19,8 @@ use std::str; /// Collected spans during parsing for places where a certain feature was /// used and should be feature gated accordingly in `check_crate`. #[derive(Default)] -crate struct GatedSpans { - crate spans: Lock>>, +pub struct GatedSpans { + pub spans: Lock>>, } impl GatedSpans { @@ -57,6 +57,15 @@ impl GatedSpans { .get(&feature) .map_or(true, |spans| spans.is_empty()) } + + /// Prepend the given set of `spans` onto the set in `self`. + pub fn merge(&self, mut spans: FxHashMap>) { + let mut inner = self.spans.borrow_mut(); + for (gate, mut gate_spans) in inner.drain() { + spans.entry(gate).or_default().append(&mut gate_spans); + } + *inner = spans; + } } /// Info about a parsing session. @@ -77,7 +86,7 @@ pub struct ParseSess { /// analysis. pub ambiguous_block_expr_parse: Lock>, pub injected_crate_name: Once, - crate gated_spans: GatedSpans, + pub gated_spans: GatedSpans, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. pub reached_eof: Lock, } 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"); diff --git a/src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs b/src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs new file mode 100644 index 00000000000..9d68a7bffde --- /dev/null +++ b/src/test/ui/parser/issue-65846-rollback-gating-failing-matcher.rs @@ -0,0 +1,14 @@ +// run-pass + +// Test that failing macro matchers will not cause pre-expansion errors +// even though they use a feature that is pre-expansion gated. + +macro_rules! m { + ($e:expr) => { 0 }; // This fails on the input below due to `, foo`. + ($e:expr,) => { 1 }; // This also fails to match due to `foo`. + (box $e:expr, foo) => { 2 }; // Successful matcher, we should get `2`. +} + +fn main() { + assert_eq!(2, m!(box 42, foo)); +} -- cgit 1.4.1-3-g733a5