From 224f080ef606560a8afddb2470c2001adf8aebe2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 17:07:42 +0200 Subject: [PATCH 1/3] Use dedicated type for spans in pre-expansion gating. --- src/libsyntax/feature_gate.rs | 15 ++++++++------ src/libsyntax/parse/attr.rs | 5 ++--- src/libsyntax/parse/mod.rs | 32 +++++++++++++++++------------- src/libsyntax/parse/parser/expr.rs | 8 ++++---- src/libsyntax/parse/parser/pat.rs | 2 +- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index bbc3ae2822558..df86ba790d6a6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2438,16 +2438,19 @@ pub fn check_crate(krate: &ast::Crate, }; macro_rules! gate_all { + ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; ($spans:ident, $gate:ident, $msg:literal) => { - for span in &*sess.$spans.borrow() { gate_feature!(&ctx, $gate, *span, $msg); } + for span in &*sess.gated_spans.$spans.borrow() { + gate_feature!(&ctx, $gate, *span, $msg); + } } } - gate_all!(param_attr_spans, param_attrs, "attributes on function parameters are unstable"); - gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental"); - gate_all!(async_closure_spans, async_closure, "async closures are unstable"); - gate_all!(yield_spans, generators, "yield syntax is experimental"); - gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental"); + gate_all!(param_attrs, "attributes on function parameters are unstable"); + 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!(or_patterns, "or-patterns syntax is experimental"); let visitor = &mut PostExpansionVisitor { context: &ctx, diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a42da1123600a..c703058e7952d 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -21,9 +21,8 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ impl<'a> Parser<'a> { crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec> { let attrs = self.parse_outer_attributes()?; - attrs.iter().for_each(|a| - self.sess.param_attr_spans.borrow_mut().push(a.span) - ); + self.sess.gated_spans.param_attrs.borrow_mut() + .extend(attrs.iter().map(|a| a.span)); Ok(attrs) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b1f3612a839a2..b1af4806e2d78 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -39,6 +39,22 @@ crate mod unescape_error_reporting; pub type PResult<'a, T> = Result>; +/// Collected spans during parsing for places where a certain feature was +/// used and should be feature gated accordingly in `check_crate`. +#[derive(Default)] +pub struct GatedSpans { + /// Spans collected for gating `param_attrs`, e.g. `fn foo(#[attr] x: u8) {}`. + pub param_attrs: Lock>, + /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. + pub let_chains: Lock>, + /// Spans collected for gating `async_closure`, e.g. `async || ..`. + pub async_closure: Lock>, + /// Spans collected for gating `yield e?` expressions (`generators` gate). + pub yields: Lock>, + /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. + pub or_patterns: Lock>, +} + /// Info about a parsing session. pub struct ParseSess { pub span_diagnostic: Handler, @@ -58,16 +74,8 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock>, - pub param_attr_spans: Lock>, - // Places where `let` exprs were used and should be feature gated according to `let_chains`. - pub let_chains_spans: Lock>, - // Places where `async || ..` exprs were used and should be feature gated. - pub async_closure_spans: Lock>, - // Places where `yield e?` exprs were used and should be feature gated. - pub yield_spans: Lock>, pub injected_crate_name: Once, - // Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated. - pub or_pattern_spans: Lock>, + pub gated_spans: GatedSpans, } impl ParseSess { @@ -93,12 +101,8 @@ impl ParseSess { buffered_lints: Lock::new(vec![]), edition: ExpnId::root().expn_data().edition, ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - param_attr_spans: Lock::new(Vec::new()), - let_chains_spans: Lock::new(Vec::new()), - async_closure_spans: Lock::new(Vec::new()), - yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), - or_pattern_spans: Lock::new(Vec::new()), + gated_spans: GatedSpans::default(), } } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index ccc6bd1506709..5da9b75d53b04 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -999,7 +999,7 @@ impl<'a> Parser<'a> { } let span = lo.to(hi); - self.sess.yield_spans.borrow_mut().push(span); + self.sess.gated_spans.yields.borrow_mut().push(span); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { @@ -1111,7 +1111,7 @@ impl<'a> Parser<'a> { }; if asyncness.is_async() { // Feature gate `async ||` closures. - self.sess.async_closure_spans.borrow_mut().push(self.prev_span); + self.sess.gated_spans.async_closure.borrow_mut().push(self.prev_span); } let capture_clause = self.parse_capture_clause(); @@ -1234,7 +1234,7 @@ impl<'a> Parser<'a> { if let ExprKind::Let(..) = cond.node { // Remove the last feature gating of a `let` expression since it's stable. - let last = self.sess.let_chains_spans.borrow_mut().pop(); + let last = self.sess.gated_spans.let_chains.borrow_mut().pop(); debug_assert_eq!(cond.span, last.unwrap()); } @@ -1252,7 +1252,7 @@ impl<'a> Parser<'a> { |this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) )?; let span = lo.to(expr.span); - self.sess.let_chains_spans.borrow_mut().push(span); + self.sess.gated_spans.let_chains.borrow_mut().push(span); Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs)) } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index fd458aec74331..8cfa6abbe6270 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -123,7 +123,7 @@ impl<'a> Parser<'a> { let or_pattern_span = lo.to(self.prev_span); - self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span); + self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } From 382f0f3155ec44447f37f0d7316c66700ec7354b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 17:47:30 +0200 Subject: [PATCH 2/3] Pre-expansion gate 'default'. --- src/libsyntax/feature_gate.rs | 15 ++------------- src/libsyntax/parse/mod.rs | 2 ++ src/libsyntax/parse/parser/item.rs | 1 + .../specialization-feature-gate-default.stderr | 6 ++---- .../specialization-feature-gate-default.rs | 10 +++++++++- .../specialization-feature-gate-default.stderr | 17 +++++++++++++---- 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index df86ba790d6a6..608cb7fd97806 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1980,19 +1980,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { + ast::ItemKind::Impl(_, polarity, ..) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, i.span, "negative trait bounds are not yet fully implemented; \ use marker types for now"); } - - if let ast::Defaultness::Default = defaultness { - gate_feature_post!(&self, specialization, - i.span, - "specialization is unstable"); - } } ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { @@ -2231,12 +2225,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { - if ii.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, - ii.span, - "specialization is unstable"); - } - match ii.node { ast::ImplItemKind::Method(..) => {} ast::ImplItemKind::OpaqueTy(..) => { @@ -2451,6 +2439,7 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(async_closure, "async closures are unstable"); gate_all!(yields, generators, "yield syntax is experimental"); gate_all!(or_patterns, "or-patterns syntax is experimental"); + gate_all!(specialization, "specialization is unstable"); let visitor = &mut PostExpansionVisitor { context: &ctx, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b1af4806e2d78..785c96571ca1e 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -53,6 +53,8 @@ pub struct GatedSpans { pub yields: Lock>, /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. pub or_patterns: Lock>, + /// Spans collected for gating the `default` qualifier for `specialization`. + pub specialization: Lock>, } /// Info about a parsing session. diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 72819c9966035..2ad5d85117bd4 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -833,6 +833,7 @@ impl<'a> Parser<'a> { ]) { self.bump(); // `default` + self.sess.gated_spans.specialization.borrow_mut().push(self.prev_span); Defaultness::Default } else { Defaultness::Final diff --git a/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr index 2cf6c586e4169..ed3d140e1ca1b 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr @@ -1,10 +1,8 @@ error[E0658]: specialization is unstable --> $DIR/specialization-feature-gate-default.rs:7:1 | -LL | / default impl Foo for T { -LL | | fn foo(&self) {} -LL | | } - | |_^ +LL | default impl Foo for T { + | ^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/31844 = help: add `#![feature(specialization)]` to the crate attributes to enable diff --git a/src/test/ui/specialization/specialization-feature-gate-default.rs b/src/test/ui/specialization/specialization-feature-gate-default.rs index 8bad3ac0a1fb3..e35cd2618b493 100644 --- a/src/test/ui/specialization/specialization-feature-gate-default.rs +++ b/src/test/ui/specialization/specialization-feature-gate-default.rs @@ -6,8 +6,16 @@ trait Foo { fn foo(&self); } +#[cfg(FALSE)] impl Foo for T { - default fn foo(&self) {} //~ ERROR specialization is unstable + default //~ ERROR specialization is unstable + fn foo(&self) {} +} + +#[cfg(FALSE)] +default //~ ERROR specialization is unstable +impl Foo for T { + fn foo(&self) {} } fn main() {} diff --git a/src/test/ui/specialization/specialization-feature-gate-default.stderr b/src/test/ui/specialization/specialization-feature-gate-default.stderr index df2ad8a9b265d..b2d2bb3bbe978 100644 --- a/src/test/ui/specialization/specialization-feature-gate-default.stderr +++ b/src/test/ui/specialization/specialization-feature-gate-default.stderr @@ -1,12 +1,21 @@ error[E0658]: specialization is unstable - --> $DIR/specialization-feature-gate-default.rs:10:5 + --> $DIR/specialization-feature-gate-default.rs:11:5 | -LL | default fn foo(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | default + | ^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/31844 = help: add `#![feature(specialization)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: specialization is unstable + --> $DIR/specialization-feature-gate-default.rs:16:1 + | +LL | default + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/31844 + = help: add `#![feature(specialization)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From b1a9e9edb1004f725d253dd3bf444fa61b74d4ca Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Aug 2019 18:10:43 +0200 Subject: [PATCH 3/3] Allow 'default async fn' to parse. --- src/libsyntax/parse/parser/item.rs | 1 + .../ui/specialization/issue-63716-parse-async.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/ui/specialization/issue-63716-parse-async.rs diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 2ad5d85117bd4..bef3bd77f93aa 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -825,6 +825,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(1, &[ kw::Impl, kw::Const, + kw::Async, kw::Fn, kw::Unsafe, kw::Extern, diff --git a/src/test/ui/specialization/issue-63716-parse-async.rs b/src/test/ui/specialization/issue-63716-parse-async.rs new file mode 100644 index 0000000000000..c3764ffaab83f --- /dev/null +++ b/src/test/ui/specialization/issue-63716-parse-async.rs @@ -0,0 +1,14 @@ +// Ensure that `default async fn` will parse. +// See issue #63716 for details. + +// check-pass +// edition:2018 + +#![feature(specialization)] + +fn main() {} + +#[cfg(FALSE)] +impl Foo for Bar { + default async fn baz() {} +}