about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-07-28 09:12:04 +0000
committerbors <bors@rust-lang.org>2019-07-28 09:12:04 +0000
commit0cfb2f7fbda1d27e12913d21d1c8e56a4133dbe1 (patch)
tree5f511147f1c0f419f26fb362c24710e1cd459ec6 /src/libsyntax
parent9a239ef4ded03d155c72b68b5a2dd7aff013e141 (diff)
parent370aa19f28ea6d42f1aaf6de39a294e5e4e9aab7 (diff)
downloadrust-0cfb2f7fbda1d27e12913d21d1c8e56a4133dbe1.tar.gz
rust-0cfb2f7fbda1d27e12913d21d1c8e56a4133dbe1.zip
Auto merge of #63074 - Centril:rollup-k1a8z0n, r=Centril
Rollup of 8 pull requests

Successful merges:

 - #62550 (Implement RFC 2707 + Parser recovery for range patterns)
 - #62759 (Actually add rustc-guide to toolstate, don't fail builds for the guide)
 - #62806 (Fix few Clippy warnings)
 - #62974 (bump crossbeam-epoch dependency)
 - #63051 (Avoid ICE when referencing desugared local binding in borrow error)
 - #63061 (In which we constantly improve the Vec(Deque) array PartialEq impls)
 - #63067 (Add test for issue-50900)
 - #63071 (Allow rustbot to add `F-*` + `requires-nightly`.)

Failed merges:

r? @ghost
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs66
-rw-r--r--src/libsyntax/ext/build.rs4
-rw-r--r--src/libsyntax/feature_gate.rs22
-rw-r--r--src/libsyntax/mut_visit.rs14
-rw-r--r--src/libsyntax/parse/parser.rs525
-rw-r--r--src/libsyntax/print/pprust.rs56
-rw-r--r--src/libsyntax/visit.rs16
7 files changed, 318 insertions, 385 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index dbfad3ef7f4..a7453f4f9da 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -519,21 +519,28 @@ impl fmt::Debug for Pat {
 }
 
 impl Pat {
+    /// Attempt reparsing the pattern as a type.
+    /// This is intended for use by diagnostics.
     pub(super) fn to_ty(&self) -> Option<P<Ty>> {
         let node = match &self.node {
+            // In a type expression `_` is an inference variable.
             PatKind::Wild => TyKind::Infer,
+            // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
             PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) => {
                 TyKind::Path(None, Path::from_ident(*ident))
             }
             PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
             PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
+            // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
             PatKind::Ref(pat, mutbl) => pat
                 .to_ty()
                 .map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
-            PatKind::Slice(pats, None, _) if pats.len() == 1 => {
-                pats[0].to_ty().map(TyKind::Slice)?
-            }
-            PatKind::Tuple(pats, None) => {
+            // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
+            // when `P` can be reparsed as a type `T`.
+            PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
+            // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
+            // assuming `T0` to `Tn` are all syntactically valid as types.
+            PatKind::Tuple(pats) => {
                 let mut tys = Vec::with_capacity(pats.len());
                 // FIXME(#48994) - could just be collected into an Option<Vec>
                 for pat in pats {
@@ -559,19 +566,15 @@ impl Pat {
             return false;
         }
 
-        match self.node {
-            PatKind::Ident(_, _, Some(ref p)) => p.walk(it),
-            PatKind::Struct(_, ref fields, _) => fields.iter().all(|field| field.node.pat.walk(it)),
-            PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
+        match &self.node {
+            PatKind::Ident(_, _, Some(p)) => p.walk(it),
+            PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.node.pat.walk(it)),
+            PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
                 s.iter().all(|p| p.walk(it))
             }
-            PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => s.walk(it),
-            PatKind::Slice(ref before, ref slice, ref after) => {
-                before.iter().all(|p| p.walk(it))
-                    && slice.iter().all(|p| p.walk(it))
-                    && after.iter().all(|p| p.walk(it))
-            }
+            PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
             PatKind::Wild
+            | PatKind::Rest
             | PatKind::Lit(_)
             | PatKind::Range(..)
             | PatKind::Ident(..)
@@ -579,6 +582,14 @@ impl Pat {
             | PatKind::Mac(_) => true,
         }
     }
+
+    /// Is this a `..` pattern?
+    pub fn is_rest(&self) -> bool {
+        match self.node {
+            PatKind::Rest => true,
+            _ => false,
+        }
+    }
 }
 
 /// A single field in a struct pattern
@@ -630,9 +641,7 @@ pub enum PatKind {
     Struct(Path, Vec<Spanned<FieldPat>>, /* recovered */ bool),
 
     /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
-    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
-    /// `0 <= position <= subpats.len()`.
-    TupleStruct(Path, Vec<P<Pat>>, Option<usize>),
+    TupleStruct(Path, Vec<P<Pat>>),
 
     /// A possibly qualified path pattern.
     /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
@@ -641,9 +650,7 @@ pub enum PatKind {
     Path(Option<QSelf>, Path),
 
     /// A tuple pattern (`(a, b)`).
-    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
-    /// `0 <= position <= subpats.len()`.
-    Tuple(Vec<P<Pat>>, Option<usize>),
+    Tuple(Vec<P<Pat>>),
 
     /// A `box` pattern.
     Box(P<Pat>),
@@ -657,9 +664,22 @@ pub enum PatKind {
     /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
     Range(P<Expr>, P<Expr>, Spanned<RangeEnd>),
 
-    /// `[a, b, ..i, y, z]` is represented as:
-    ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`
-    Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
+    /// A slice pattern `[a, b, c]`.
+    Slice(Vec<P<Pat>>),
+
+    /// A rest pattern `..`.
+    ///
+    /// Syntactically it is valid anywhere.
+    ///
+    /// Semantically however, it only has meaning immediately inside:
+    /// - a slice pattern: `[a, .., b]`,
+    /// - a binding pattern immediately inside a slice pattern: `[a, r @ ..]`,
+    /// - a tuple pattern: `(a, .., b)`,
+    /// - a tuple struct/variant pattern: `$path(a, .., b)`.
+    ///
+    /// In all of these cases, an additional restriction applies,
+    /// only one rest pattern may occur in the pattern sequences.
+    Rest,
 
     /// Parentheses in patterns used for grouping (i.e., `(PAT)`).
     Paren(P<Pat>),
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index baf1031de1e..528b27d6153 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -840,14 +840,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
     fn pat_tuple_struct(&self, span: Span, path: ast::Path,
                         subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
-        self.pat(span, PatKind::TupleStruct(path, subpats, None))
+        self.pat(span, PatKind::TupleStruct(path, subpats))
     }
     fn pat_struct(&self, span: Span, path: ast::Path,
                   field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
         self.pat(span, PatKind::Struct(path, field_pats, false))
     }
     fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
-        self.pat(span, PatKind::Tuple(pats, None))
+        self.pat(span, PatKind::Tuple(pats))
     }
 
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 72184b0bd64..384474b08f6 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -2151,11 +2151,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     }
 
     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
-        match pattern.node {
-            PatKind::Slice(_, Some(ref subslice), _) => {
-                gate_feature_post!(&self, slice_patterns,
-                                   subslice.span,
-                                   "syntax for subslices in slice patterns is not yet stabilized");
+        match &pattern.node {
+            PatKind::Slice(pats) => {
+                for pat in &*pats {
+                    let span = pat.span;
+                    let inner_pat = match &pat.node {
+                        PatKind::Ident(.., Some(pat)) => pat,
+                        _ => pat,
+                    };
+                    if inner_pat.is_rest() {
+                        gate_feature_post!(
+                            &self,
+                            slice_patterns,
+                            span,
+                            "subslice patterns are unstable"
+                        );
+                    }
+                }
             }
             PatKind::Box(..) => {
                 gate_feature_post!(&self, box_patterns,
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index dc656222fbc..86525406718 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -1020,15 +1020,15 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
     let Pat { id, node, span } = pat.deref_mut();
     vis.visit_id(id);
     match node {
-        PatKind::Wild => {}
+        PatKind::Wild | PatKind::Rest => {}
         PatKind::Ident(_binding_mode, ident, sub) => {
             vis.visit_ident(ident);
             visit_opt(sub, |sub| vis.visit_pat(sub));
         }
         PatKind::Lit(e) => vis.visit_expr(e),
-        PatKind::TupleStruct(path, pats, _ddpos) => {
+        PatKind::TupleStruct(path, elems) => {
             vis.visit_path(path);
-            visit_vec(pats, |pat| vis.visit_pat(pat));
+            visit_vec(elems, |elem| vis.visit_pat(elem));
         }
         PatKind::Path(qself, path) => {
             vis.visit_qself(qself);
@@ -1043,7 +1043,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
                 vis.visit_span(span);
             };
         }
-        PatKind::Tuple(elts, _ddpos) => visit_vec(elts, |elt| vis.visit_pat(elt)),
+        PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
         PatKind::Box(inner) => vis.visit_pat(inner),
         PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
         PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
@@ -1051,11 +1051,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             vis.visit_expr(e2);
             vis.visit_span(span);
         }
-        PatKind::Slice(before, slice, after) => {
-            visit_vec(before, |pat| vis.visit_pat(pat));
-            visit_opt(slice, |slice| vis.visit_pat(slice));
-            visit_vec(after, |pat| vis.visit_pat(pat));
-        }
+        PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
         PatKind::Paren(inner) => vis.visit_pat(inner),
         PatKind::Mac(mac) => vis.visit_mac(mac),
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a5b6f0d6836..8f8ed411180 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -890,14 +890,13 @@ impl<'a> Parser<'a> {
     /// Parses a sequence, including the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
-    pub fn parse_seq_to_end<T, F>(&mut self,
-                                  ket: &TokenKind,
-                                  sep: SeqSep,
-                                  f: F)
-                                  -> PResult<'a, Vec<T>> where
-        F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
-    {
-        let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
+    pub fn parse_seq_to_end<T>(
+        &mut self,
+        ket: &TokenKind,
+        sep: SeqSep,
+        f: impl FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
+    ) -> PResult<'a, Vec<T>> {
+        let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
         if !recovered {
             self.bump();
         }
@@ -907,39 +906,39 @@ impl<'a> Parser<'a> {
     /// Parses a sequence, not including the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
-    pub fn parse_seq_to_before_end<T, F>(
+    pub fn parse_seq_to_before_end<T>(
         &mut self,
         ket: &TokenKind,
         sep: SeqSep,
-        f: F,
-    ) -> PResult<'a, (Vec<T>, bool)>
-        where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
-    {
+        f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> PResult<'a, (Vec<T>, bool, bool)> {
         self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
     }
 
-    crate fn parse_seq_to_before_tokens<T, F>(
+    fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
+        kets.iter().any(|k| {
+            match expect {
+                TokenExpectType::Expect => self.check(k),
+                TokenExpectType::NoExpect => self.token == **k,
+            }
+        })
+    }
+
+    crate fn parse_seq_to_before_tokens<T>(
         &mut self,
         kets: &[&TokenKind],
         sep: SeqSep,
         expect: TokenExpectType,
-        mut f: F,
-    ) -> PResult<'a, (Vec<T>, bool /* recovered */)>
-        where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
-    {
+        mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> PResult<'a, (Vec<T>, bool /* trailing */, bool /* recovered */)> {
         let mut first = true;
         let mut recovered = false;
+        let mut trailing = false;
         let mut v = vec![];
-        while !kets.iter().any(|k| {
-                match expect {
-                    TokenExpectType::Expect => self.check(k),
-                    TokenExpectType::NoExpect => self.token == **k,
-                }
-            }) {
-            match self.token.kind {
-                token::CloseDelim(..) | token::Eof => break,
-                _ => {}
-            };
+        while !self.expect_any_with_type(kets, expect) {
+            if let token::CloseDelim(..) | token::Eof = self.token.kind {
+                break
+            }
             if let Some(ref t) = sep.sep {
                 if first {
                     first = false;
@@ -973,12 +972,8 @@ impl<'a> Parser<'a> {
                     }
                 }
             }
-            if sep.trailing_sep_allowed && kets.iter().any(|k| {
-                match expect {
-                    TokenExpectType::Expect => self.check(k),
-                    TokenExpectType::NoExpect => self.token == **k,
-                }
-            }) {
+            if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) {
+                trailing = true;
                 break;
             }
 
@@ -986,27 +981,45 @@ impl<'a> Parser<'a> {
             v.push(t);
         }
 
-        Ok((v, recovered))
+        Ok((v, trailing, recovered))
     }
 
     /// Parses a sequence, including the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
-    fn parse_unspanned_seq<T, F>(
+    fn parse_unspanned_seq<T>(
         &mut self,
         bra: &TokenKind,
         ket: &TokenKind,
         sep: SeqSep,
-        f: F,
-    ) -> PResult<'a, Vec<T>> where
-        F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    {
+        f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> PResult<'a, (Vec<T>, bool)> {
         self.expect(bra)?;
-        let (result, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
+        let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
         if !recovered {
             self.eat(ket);
         }
-        Ok(result)
+        Ok((result, trailing))
+    }
+
+    fn parse_delim_comma_seq<T>(
+        &mut self,
+        delim: DelimToken,
+        f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> PResult<'a, (Vec<T>, bool)> {
+        self.parse_unspanned_seq(
+            &token::OpenDelim(delim),
+            &token::CloseDelim(delim),
+            SeqSep::trailing_allowed(token::Comma),
+            f,
+        )
+    }
+
+    fn parse_paren_comma_seq<T>(
+        &mut self,
+        f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+    ) -> PResult<'a, (Vec<T>, bool)> {
+        self.parse_delim_comma_seq(token::Paren, f)
     }
 
     /// Advance the parser by one token
@@ -1804,15 +1817,7 @@ impl<'a> Parser<'a> {
                 AngleBracketedArgs { args, constraints, span }.into()
             } else {
                 // `(T, U) -> R`
-                self.bump(); // `(`
-                let (inputs, recovered) = self.parse_seq_to_before_tokens(
-                    &[&token::CloseDelim(token::Paren)],
-                    SeqSep::trailing_allowed(token::Comma),
-                    TokenExpectType::Expect,
-                    |p| p.parse_ty())?;
-                if !recovered {
-                    self.bump(); // `)`
-                }
+                let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
                 let span = lo.to(self.prev_span);
                 let output = if self.eat(&token::RArrow) {
                     Some(self.parse_ty_common(false, false, false)?)
@@ -2516,12 +2521,7 @@ impl<'a> Parser<'a> {
         Ok(match self.token.kind {
             token::OpenDelim(token::Paren) => {
                 // Method call `expr.f()`
-                let mut args = self.parse_unspanned_seq(
-                    &token::OpenDelim(token::Paren),
-                    &token::CloseDelim(token::Paren),
-                    SeqSep::trailing_allowed(token::Comma),
-                    |p| Ok(p.parse_expr()?)
-                )?;
+                let mut args = self.parse_paren_expr_seq()?;
                 args.insert(0, self_arg);
 
                 let span = lo.to(self.prev_span);
@@ -2606,12 +2606,7 @@ impl<'a> Parser<'a> {
             match self.token.kind {
                 // expr(...)
                 token::OpenDelim(token::Paren) => {
-                    let seq = self.parse_unspanned_seq(
-                        &token::OpenDelim(token::Paren),
-                        &token::CloseDelim(token::Paren),
-                        SeqSep::trailing_allowed(token::Comma),
-                        |p| Ok(p.parse_expr()?)
-                    ).map(|es| {
+                    let seq = self.parse_paren_expr_seq().map(|es| {
                         let nd = self.mk_call(e, es);
                         let hi = self.prev_span;
                         self.mk_expr(lo.to(hi), nd, ThinVec::new())
@@ -2635,6 +2630,10 @@ impl<'a> Parser<'a> {
         return Ok(e);
     }
 
+    fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec<P<Expr>>> {
+        self.parse_paren_comma_seq(|p| p.parse_expr()).map(|(r, _)| r)
+    }
+
     crate fn process_potential_macro_variable(&mut self) {
         self.token = match self.token.kind {
             token::Dollar if self.token.span.ctxt() != SyntaxContext::empty() &&
@@ -3536,122 +3535,6 @@ impl<'a> Parser<'a> {
         };
     }
 
-    // Parses a parenthesized list of patterns like
-    // `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
-    // - a vector of the patterns that were parsed
-    // - an option indicating the index of the `..` element
-    // - a boolean indicating whether a trailing comma was present.
-    // Trailing commas are significant because (p) and (p,) are different patterns.
-    fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
-        self.expect(&token::OpenDelim(token::Paren))?;
-        let result = match self.parse_pat_list() {
-            Ok(result) => result,
-            Err(mut err) => { // recover from parse error in tuple pattern list
-                err.emit();
-                self.consume_block(token::Paren);
-                return Ok((vec![], Some(0), false));
-            }
-        };
-        self.expect(&token::CloseDelim(token::Paren))?;
-        Ok(result)
-    }
-
-    fn parse_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
-        let mut fields = Vec::new();
-        let mut ddpos = None;
-        let mut prev_dd_sp = None;
-        let mut trailing_comma = false;
-        loop {
-            if self.eat(&token::DotDot) {
-                if ddpos.is_none() {
-                    ddpos = Some(fields.len());
-                    prev_dd_sp = Some(self.prev_span);
-                } else {
-                    // Emit a friendly error, ignore `..` and continue parsing
-                    let mut err = self.struct_span_err(
-                        self.prev_span,
-                        "`..` can only be used once per tuple or tuple struct pattern",
-                    );
-                    err.span_label(self.prev_span, "can only be used once per pattern");
-                    if let Some(sp) = prev_dd_sp {
-                        err.span_label(sp, "previously present here");
-                    }
-                    err.emit();
-                }
-            } else if !self.check(&token::CloseDelim(token::Paren)) {
-                fields.push(self.parse_pat(None)?);
-            } else {
-                break
-            }
-
-            trailing_comma = self.eat(&token::Comma);
-            if !trailing_comma {
-                break
-            }
-        }
-
-        if ddpos == Some(fields.len()) && trailing_comma {
-            // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
-            let msg = "trailing comma is not permitted after `..`";
-            self.struct_span_err(self.prev_span, msg)
-                .span_label(self.prev_span, msg)
-                .emit();
-        }
-
-        Ok((fields, ddpos, trailing_comma))
-    }
-
-    fn parse_pat_vec_elements(
-        &mut self,
-    ) -> PResult<'a, (Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>)> {
-        let mut before = Vec::new();
-        let mut slice = None;
-        let mut after = Vec::new();
-        let mut first = true;
-        let mut before_slice = true;
-
-        while self.token != token::CloseDelim(token::Bracket) {
-            if first {
-                first = false;
-            } else {
-                self.expect(&token::Comma)?;
-
-                if self.token == token::CloseDelim(token::Bracket)
-                        && (before_slice || !after.is_empty()) {
-                    break
-                }
-            }
-
-            if before_slice {
-                if self.eat(&token::DotDot) {
-
-                    if self.check(&token::Comma) ||
-                            self.check(&token::CloseDelim(token::Bracket)) {
-                        slice = Some(P(Pat {
-                            id: ast::DUMMY_NODE_ID,
-                            node: PatKind::Wild,
-                            span: self.prev_span,
-                        }));
-                        before_slice = false;
-                    }
-                    continue
-                }
-            }
-
-            let subpat = self.parse_pat(None)?;
-            if before_slice && self.eat(&token::DotDot) {
-                slice = Some(subpat);
-                before_slice = false;
-            } else if before_slice {
-                before.push(subpat);
-            } else {
-                after.push(subpat);
-            }
-        }
-
-        Ok((before, slice, after))
-    }
-
     fn parse_pat_field(
         &mut self,
         lo: Span,
@@ -3847,20 +3730,34 @@ impl<'a> Parser<'a> {
         }
     }
 
-    // helper function to decide whether to parse as ident binding or to try to do
-    // something more complex like range patterns
+    /// Is the current token suitable as the start of a range patterns end?
+    fn is_pat_range_end_start(&self) -> bool {
+        self.token.is_path_start() // e.g. `MY_CONST`;
+            || self.token == token::Dot // e.g. `.5` for recovery;
+            || self.token.can_begin_literal_or_bool() // e.g. `42`.
+    }
+
+    // Helper function to decide whether to parse as ident binding
+    // or to try to do something more complex like range patterns.
     fn parse_as_ident(&mut self) -> bool {
         self.look_ahead(1, |t| match t.kind {
             token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
-            token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false),
-            // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the
-            // range pattern branch
-            token::DotDot => None,
-            _ => Some(true),
-        }).unwrap_or_else(|| self.look_ahead(2, |t| match t.kind {
-            token::Comma | token::CloseDelim(token::Bracket) => true,
-            _ => false,
-        }))
+            token::DotDotDot | token::DotDotEq | token::DotDot |
+            token::ModSep | token::Not => false,
+            _ => true,
+        })
+    }
+
+    /// Parse and throw away a parentesized comma separated
+    /// sequence of patterns until `)` is reached.
+    fn skip_pat_list(&mut self) -> PResult<'a, ()> {
+        while !self.check(&token::CloseDelim(token::Paren)) {
+            self.parse_pat(None)?;
+            if !self.eat(&token::Comma) {
+                return Ok(())
+            }
+        }
+        Ok(())
     }
 
     /// A wrapper around `parse_pat` with some special error handling for the
@@ -3876,7 +3773,7 @@ impl<'a> Parser<'a> {
             // later.
             let comma_span = self.token.span;
             self.bump();
-            if let Err(mut err) = self.parse_pat_list() {
+            if let Err(mut err) = self.skip_pat_list() {
                 // We didn't expect this to work anyway; we just wanted
                 // to advance to the end of the comma-sequence so we know
                 // the span to suggest parenthesizing
@@ -3908,6 +3805,53 @@ impl<'a> Parser<'a> {
         self.parse_pat_with_range_pat(true, expected)
     }
 
+    /// Parse a range-to pattern, e.g. `..X` and `..=X` for recovery.
+    fn parse_pat_range_to(&mut self, re: RangeEnd, form: &str) -> PResult<'a, PatKind> {
+        let lo = self.prev_span;
+        let end = self.parse_pat_range_end()?;
+        let range_span = lo.to(end.span);
+        let begin = self.mk_expr(range_span, ExprKind::Err, ThinVec::new());
+
+        self.diagnostic()
+            .struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form))
+            .span_suggestion(
+                range_span,
+                "try using the minimum value for the type",
+                format!("MIN{}{}", form, pprust::expr_to_string(&end)),
+                Applicability::HasPlaceholders,
+            )
+            .emit();
+
+        Ok(PatKind::Range(begin, end, respan(lo, re)))
+    }
+
+    /// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern  or recover
+    /// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
+    fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
+        if self.is_pat_range_end_start() {
+            // Parsing e.g. `X..=Y`.
+            self.parse_pat_range_end()
+        } else {
+            // Parsing e.g. `X..`.
+            let range_span = begin.span.to(self.prev_span);
+
+            self.diagnostic()
+                .struct_span_err(
+                    range_span,
+                    &format!("`X{}` range patterns are not supported", form),
+                )
+                .span_suggestion(
+                    range_span,
+                    "try using the maximum value for the type",
+                    format!("{}{}MAX", pprust::expr_to_string(&begin), form),
+                    Applicability::HasPlaceholders,
+                )
+                .emit();
+
+            Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
+        }
+    }
+
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
@@ -3934,20 +3878,41 @@ impl<'a> Parser<'a> {
                 pat = PatKind::Ref(subpat, mutbl);
             }
             token::OpenDelim(token::Paren) => {
-                // Parse (pat,pat,pat,...) as tuple pattern
-                let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
-                pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
+                // Parse a tuple or parenthesis pattern.
+                let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
+
+                // Here, `(pat,)` is a tuple pattern.
+                // For backward compatibility, `(..)` is a tuple pattern as well.
+                pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
                     PatKind::Paren(fields.into_iter().nth(0).unwrap())
                 } else {
-                    PatKind::Tuple(fields, ddpos)
+                    PatKind::Tuple(fields)
                 };
             }
             token::OpenDelim(token::Bracket) => {
-                // Parse [pat,pat,...] as slice pattern
+                // Parse `[pat, pat,...]` as a slice pattern.
+                let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?;
+                pat = PatKind::Slice(slice);
+            }
+            token::DotDot => {
+                self.bump();
+                pat = if self.is_pat_range_end_start() {
+                    // Parse `..42` for recovery.
+                    self.parse_pat_range_to(RangeEnd::Excluded, "..")?
+                } else {
+                    // A rest pattern `..`.
+                    PatKind::Rest
+                };
+            }
+            token::DotDotEq => {
+                // Parse `..=42` for recovery.
                 self.bump();
-                let (before, slice, after) = self.parse_pat_vec_elements()?;
-                self.expect(&token::CloseDelim(token::Bracket))?;
-                pat = PatKind::Slice(before, slice, after);
+                pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?;
+            }
+            token::DotDotDot => {
+                // Parse `...42` for recovery.
+                self.bump();
+                pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?;
             }
             // At this point, token != &, &&, (, [
             _ => if self.eat_keyword(kw::Underscore) {
@@ -4004,10 +3969,10 @@ impl<'a> Parser<'a> {
                         pat = PatKind::Mac(mac);
                     }
                     token::DotDotDot | token::DotDotEq | token::DotDot => {
-                        let end_kind = match self.token.kind {
-                            token::DotDot => RangeEnd::Excluded,
-                            token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot),
-                            token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq),
+                        let (end_kind, form) = match self.token.kind {
+                            token::DotDot => (RangeEnd::Excluded, ".."),
+                            token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
+                            token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
                             _ => panic!("can only parse `..`/`...`/`..=` for ranges \
                                          (checked above)"),
                         };
@@ -4016,9 +3981,8 @@ impl<'a> Parser<'a> {
                         let span = lo.to(self.prev_span);
                         let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
                         self.bump();
-                        let end = self.parse_pat_range_end()?;
-                        let op = Spanned { span: op_span, node: end_kind };
-                        pat = PatKind::Range(begin, end, op);
+                        let end = self.parse_pat_range_end_opt(&begin, form)?;
+                        pat = PatKind::Range(begin, end, respan(op_span, end_kind));
                     }
                     token::OpenDelim(token::Brace) => {
                         if qself.is_some() {
@@ -4045,8 +4009,8 @@ impl<'a> Parser<'a> {
                             return Err(err);
                         }
                         // Parse tuple struct or enum pattern
-                        let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
-                        pat = PatKind::TupleStruct(path, fields, ddpos)
+                        let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
+                        pat = PatKind::TupleStruct(path, fields)
                     }
                     _ => pat = PatKind::Path(qself, path),
                 }
@@ -4057,19 +4021,18 @@ impl<'a> Parser<'a> {
                         let op_span = self.token.span;
                         if self.check(&token::DotDot) || self.check(&token::DotDotEq) ||
                                 self.check(&token::DotDotDot) {
-                            let end_kind = if self.eat(&token::DotDotDot) {
-                                RangeEnd::Included(RangeSyntax::DotDotDot)
+                            let (end_kind, form) = if self.eat(&token::DotDotDot) {
+                                (RangeEnd::Included(RangeSyntax::DotDotDot), "...")
                             } else if self.eat(&token::DotDotEq) {
-                                RangeEnd::Included(RangeSyntax::DotDotEq)
+                                (RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
                             } else if self.eat(&token::DotDot) {
-                                RangeEnd::Excluded
+                                (RangeEnd::Excluded, "..")
                             } else {
                                 panic!("impossible case: we already matched \
                                         on a range-operator token")
                             };
-                            let end = self.parse_pat_range_end()?;
-                            let op = Spanned { span: op_span, node: end_kind };
-                            pat = PatKind::Range(begin, end, op);
+                            let end = self.parse_pat_range_end_opt(&begin, form)?;
+                            pat = PatKind::Range(begin, end, respan(op_span, end_kind))
                         } else {
                             pat = PatKind::Lit(begin);
                         }
@@ -5359,59 +5322,48 @@ impl<'a> Parser<'a> {
 
     fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool)
                      -> PResult<'a, (Vec<Arg> , bool)> {
-        self.expect(&token::OpenDelim(token::Paren))?;
-
         let sp = self.token.span;
         let mut c_variadic = false;
-        let (args, recovered): (Vec<Option<Arg>>, bool) =
-            self.parse_seq_to_before_end(
-                &token::CloseDelim(token::Paren),
-                SeqSep::trailing_allowed(token::Comma),
-                |p| {
-                    let do_not_enforce_named_arguments_for_c_variadic =
-                        |token: &token::Token| -> bool {
-                            if token == &token::DotDotDot {
-                                false
-                            } else {
-                                named_args
-                            }
-                        };
-                    match p.parse_arg_general(
-                        false,
-                        allow_c_variadic,
-                        do_not_enforce_named_arguments_for_c_variadic
-                    ) {
-                        Ok(arg) => {
-                            if let TyKind::CVarArgs = arg.ty.node {
-                                c_variadic = true;
-                                if p.token != token::CloseDelim(token::Paren) {
-                                    let span = p.token.span;
-                                    p.span_err(span,
-                                        "`...` must be the last argument of a C-variadic function");
-                                    Ok(None)
-                                } else {
-                                    Ok(Some(arg))
-                                }
-                            } else {
-                                Ok(Some(arg))
-                            }
-                        },
-                        Err(mut e) => {
-                            e.emit();
-                            let lo = p.prev_span;
-                            // Skip every token until next possible arg or end.
-                            p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
-                            // Create a placeholder argument for proper arg count (issue #34264).
-                            let span = lo.to(p.prev_span);
-                            Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
+        let (args, _): (Vec<Option<Arg>>, _) = self.parse_paren_comma_seq(|p| {
+            let do_not_enforce_named_arguments_for_c_variadic =
+                |token: &token::Token| -> bool {
+                    if token == &token::DotDotDot {
+                        false
+                    } else {
+                        named_args
+                    }
+                };
+            match p.parse_arg_general(
+                false,
+                allow_c_variadic,
+                do_not_enforce_named_arguments_for_c_variadic
+            ) {
+                Ok(arg) => {
+                    if let TyKind::CVarArgs = arg.ty.node {
+                        c_variadic = true;
+                        if p.token != token::CloseDelim(token::Paren) {
+                            let span = p.token.span;
+                            p.span_err(span,
+                                "`...` must be the last argument of a C-variadic function");
+                            Ok(None)
+                        } else {
+                            Ok(Some(arg))
                         }
+                    } else {
+                        Ok(Some(arg))
                     }
+                },
+                Err(mut e) => {
+                    e.emit();
+                    let lo = p.prev_span;
+                    // Skip every token until next possible arg or end.
+                    p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+                    // Create a placeholder argument for proper arg count (issue #34264).
+                    let span = lo.to(p.prev_span);
+                    Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
                 }
-            )?;
-
-        if !recovered {
-            self.eat(&token::CloseDelim(token::Paren));
-        }
+            }
+        })?;
 
         let args: Vec<_> = args.into_iter().filter_map(|x| x).collect();
 
@@ -5573,7 +5525,7 @@ impl<'a> Parser<'a> {
                 (vec![self_arg], false)
             } else if self.eat(&token::Comma) {
                 let mut fn_inputs = vec![self_arg];
-                let (mut input, recovered) = self.parse_seq_to_before_end(
+                let (mut input, _, recovered) = self.parse_seq_to_before_end(
                     &token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
                 fn_inputs.append(&mut input);
                 (fn_inputs, recovered)
@@ -5584,7 +5536,9 @@ impl<'a> Parser<'a> {
                 }
             }
         } else {
-            self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
+            let (input, _, recovered) =
+                self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
+            (input, recovered)
         };
 
         if !recovered {
@@ -6185,26 +6139,20 @@ impl<'a> Parser<'a> {
     fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
         // This is the case where we find `struct Foo<T>(T) where T: Copy;`
         // Unit like structs are handled in parse_item_struct function
-        let fields = self.parse_unspanned_seq(
-            &token::OpenDelim(token::Paren),
-            &token::CloseDelim(token::Paren),
-            SeqSep::trailing_allowed(token::Comma),
-            |p| {
-                let attrs = p.parse_outer_attributes()?;
-                let lo = p.token.span;
-                let vis = p.parse_visibility(true)?;
-                let ty = p.parse_ty()?;
-                Ok(StructField {
-                    span: lo.to(ty.span),
-                    vis,
-                    ident: None,
-                    id: ast::DUMMY_NODE_ID,
-                    ty,
-                    attrs,
-                })
-            })?;
-
-        Ok(fields)
+        self.parse_paren_comma_seq(|p| {
+            let attrs = p.parse_outer_attributes()?;
+            let lo = p.token.span;
+            let vis = p.parse_visibility(true)?;
+            let ty = p.parse_ty()?;
+            Ok(StructField {
+                span: lo.to(ty.span),
+                vis,
+                ident: None,
+                id: ast::DUMMY_NODE_ID,
+                ty,
+                attrs,
+            })
+        }).map(|(r, _)| r)
     }
 
     /// Parses a structure field declaration.
@@ -7786,11 +7734,8 @@ impl<'a> Parser<'a> {
     /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
     /// ```
     fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
-        self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
-                                 &token::CloseDelim(token::Brace),
-                                 SeqSep::trailing_allowed(token::Comma), |this| {
-            Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID))
-        })
+        self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID)))
+            .map(|(r, _)| r)
     }
 
     fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c4623576395..c7be0b12302 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2368,22 +2368,10 @@ impl<'a> State<'a> {
                     self.print_pat(p);
                 }
             }
-            PatKind::TupleStruct(ref path, ref elts, ddpos) => {
+            PatKind::TupleStruct(ref path, ref elts) => {
                 self.print_path(path, true, 0);
                 self.popen();
-                if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
-                    if ddpos != 0 {
-                        self.word_space(",");
-                    }
-                    self.s.word("..");
-                    if ddpos != elts.len() {
-                        self.s.word(",");
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
-                    }
-                } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
-                }
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
                 self.pclose();
             }
             PatKind::Path(None, ref path) => {
@@ -2415,23 +2403,11 @@ impl<'a> State<'a> {
                 self.s.space();
                 self.s.word("}");
             }
-            PatKind::Tuple(ref elts, ddpos) => {
+            PatKind::Tuple(ref elts) => {
                 self.popen();
-                if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
-                    if ddpos != 0 {
-                        self.word_space(",");
-                    }
-                    self.s.word("..");
-                    if ddpos != elts.len() {
-                        self.s.word(",");
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
-                    }
-                } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
-                    if elts.len() == 1 {
-                        self.s.word(",");
-                    }
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+                if elts.len() == 1 {
+                    self.s.word(",");
                 }
                 self.pclose();
             }
@@ -2457,26 +2433,12 @@ impl<'a> State<'a> {
                 }
                 self.print_expr(end);
             }
-            PatKind::Slice(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref elts) => {
                 self.s.word("[");
-                self.commasep(Inconsistent,
-                                   &before[..],
-                                   |s, p| s.print_pat(p));
-                if let Some(ref p) = *slice {
-                    if !before.is_empty() { self.word_space(","); }
-                    if let PatKind::Wild = p.node {
-                        // Print nothing
-                    } else {
-                        self.print_pat(p);
-                    }
-                    self.s.word("..");
-                    if !after.is_empty() { self.word_space(","); }
-                }
-                self.commasep(Inconsistent,
-                                   &after[..],
-                                   |s, p| s.print_pat(p));
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
                 self.s.word("]");
             }
+            PatKind::Rest => self.s.word(".."),
             PatKind::Paren(ref inner) => {
                 self.popen();
                 self.print_pat(inner);
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 9ec9550f93a..ff6440fb9dc 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -428,9 +428,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V,
 
 pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
     match pattern.node {
-        PatKind::TupleStruct(ref path, ref children, _) => {
+        PatKind::TupleStruct(ref path, ref elems) => {
             visitor.visit_path(path, pattern.id);
-            walk_list!(visitor, visit_pat, children);
+            walk_list!(visitor, visit_pat, elems);
         }
         PatKind::Path(ref opt_qself, ref path) => {
             if let Some(ref qself) = *opt_qself {
@@ -446,8 +446,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
                 visitor.visit_pat(&field.node.pat)
             }
         }
-        PatKind::Tuple(ref tuple_elements, _) => {
-            walk_list!(visitor, visit_pat, tuple_elements);
+        PatKind::Tuple(ref elems) => {
+            walk_list!(visitor, visit_pat, elems);
         }
         PatKind::Box(ref subpattern) |
         PatKind::Ref(ref subpattern, _) |
@@ -463,11 +463,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
             visitor.visit_expr(lower_bound);
             visitor.visit_expr(upper_bound);
         }
-        PatKind::Wild => (),
-        PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
-            walk_list!(visitor, visit_pat, prepatterns);
-            walk_list!(visitor, visit_pat, slice_pattern);
-            walk_list!(visitor, visit_pat, postpatterns);
+        PatKind::Wild | PatKind::Rest => {},
+        PatKind::Slice(ref elems) => {
+            walk_list!(visitor, visit_pat, elems);
         }
         PatKind::Mac(ref mac) => visitor.visit_mac(mac),
     }