diff --git a/src/doc/unstable-book/src/language-features/match-beginning-vert.md b/src/doc/unstable-book/src/language-features/match-beginning-vert.md new file mode 100644 index 00000000000..6ef1ab38e8d --- /dev/null +++ b/src/doc/unstable-book/src/language-features/match-beginning-vert.md @@ -0,0 +1,21 @@ +# `match_beginning_vert` + +The tracking issue for this feature is [#44101]. + +With this feature enabled, you are allowed to add a '|' to the beginning of a +match arm: + +```rust +#![feature(match_beginning_vert)] + +enum Foo { A, B } + +fn main() { + let x = Foo::A; + match x { + | A | B => {}, + } +} +``` + +[#44101]: https://github.com/rust-lang/rust/issues/44101 \ No newline at end of file diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 925178f8639..720f6cd32bd 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -810,6 +810,7 @@ pub struct Arm { pub pats: Vec>, pub guard: Option>, pub body: P, + pub beginning_vert: Option, // For RFC 1925 feature gate } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 66df734b328..48d789372a0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -878,7 +878,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attrs: vec![], pats, guard: None, - body: expr + body: expr, + beginning_vert: None, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8251b03632a..adef4942b67 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -379,6 +379,9 @@ declare_features! ( // allow `#[must_use]` on functions (RFC 1940) (active, fn_must_use, "1.21.0", Some(43302)), + + // allow '|' at beginning of match arms (RFC 1925) + (active, match_beginning_vert, "1.21.0", Some(44101)), ); declare_features! ( @@ -1435,6 +1438,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_expr(self, e); } + fn visit_arm(&mut self, arm: &'a ast::Arm) { + if let Some(span) = arm.beginning_vert { + gate_feature_post!(&self, match_beginning_vert, + span, + "Use of a '|' at the beginning of a match arm is experimental") + } + } + fn visit_pat(&mut self, pattern: &'a ast::Pat) { match pattern.node { PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d9f453a93ad..03c47b71d02 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -344,12 +344,14 @@ pub fn fold_thin_attrs(attrs: ThinVec, fld: &mut T) -> Thi fold_attrs(attrs.into(), fld).into() } -pub fn noop_fold_arm(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm { +pub fn noop_fold_arm(Arm {attrs, pats, guard, body, beginning_vert}: Arm, + fld: &mut T) -> Arm { Arm { attrs: fold_attrs(attrs, fld), pats: pats.move_map(|x| fld.fold_pat(x)), guard: guard.map(|x| fld.fold_expr(x)), body: fld.fold_expr(body), + beginning_vert, } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d08373334f1..1f033b25fe4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3155,6 +3155,12 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtArm, |x| x); let attrs = self.parse_outer_attributes()?; + // Allow a '|' before the pats (RFC 1925) + let beginning_vert = if self.eat(&token::BinOp(token::Or)) { + Some(self.prev_span) + } else { + None + }; let pats = self.parse_pats()?; let guard = if self.eat_keyword(keywords::If) { Some(self.parse_expr()?) @@ -3178,6 +3184,7 @@ impl<'a> Parser<'a> { pats, guard, body: expr, + beginning_vert, }) } diff --git a/src/test/compile-fail/feature-gate-match_beginning_vert.rs b/src/test/compile-fail/feature-gate-match_beginning_vert.rs new file mode 100644 index 00000000000..9085563c99d --- /dev/null +++ b/src/test/compile-fail/feature-gate-match_beginning_vert.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(dead_code)] +enum Foo { + A, + B, + C, + D, + E, +} +use Foo::*; + +fn main() { + let x = Foo::A; + match x { + | A => println!("A"), + //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) + | B | C => println!("BC!"), + //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) + | _ => {}, + //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) + }; + match x { + A | B | C => println!("ABC!"), + _ => {}, + }; +} +