about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorArtyom Pavlov <newpavlov@gmail.com>2019-08-20 10:08:57 +0000
committerGitHub <noreply@github.com>2019-08-20 10:08:57 +0000
commite500fc3171a899f713a269ccee6f480b9db4859b (patch)
tree8aa95c5dd723ddc09ffbe724c44cb701f8bde7e5 /src/libsyntax
parent34c9f8c6490bb1179c504bccd51b2827c05f10db (diff)
parent7858dc237d70fc0c5a31eb528dfab1ad0baf6a27 (diff)
Merge branch 'master' into redox_builder
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs11
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs25
-rw-r--r--src/libsyntax/ext/placeholders.rs7
-rw-r--r--src/libsyntax/feature_gate.rs5
-rw-r--r--src/libsyntax/mut_visit.rs5
-rw-r--r--src/libsyntax/parse/lexer/mod.rs81
-rw-r--r--src/libsyntax/parse/mod.rs3
-rw-r--r--src/libsyntax/parse/parser/pat.rs41
-rw-r--r--src/libsyntax/print/pprust.rs36
-rw-r--r--src/libsyntax/visit.rs7
11 files changed, 116 insertions, 113 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 9091607629e..50e428ea0cc 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -572,9 +572,10 @@ impl Pat {
         match &self.node {
             PatKind::Ident(_, _, Some(p)) => p.walk(it),
             PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk(it)),
-            PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
-                s.iter().all(|p| p.walk(it))
-            }
+            PatKind::TupleStruct(_, s)
+            | PatKind::Tuple(s)
+            | PatKind::Slice(s)
+            | PatKind::Or(s) => s.iter().all(|p| p.walk(it)),
             PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
             PatKind::Wild
             | PatKind::Rest
@@ -648,6 +649,10 @@ pub enum PatKind {
     /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
     TupleStruct(Path, Vec<P<Pat>>),
 
+    /// An or-pattern `A | B | C`.
+    /// Invariant: `pats.len() >= 2`.
+    Or(Vec<P<Pat>>),
+
     /// A possibly qualified path pattern.
     /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
     /// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index fb1bf4d7160..b0a4a6af983 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1,4 +1,4 @@
-use crate::ast::{self, Attribute, Name, PatKind};
+use crate::ast::{self, NodeId, Attribute, Name, PatKind};
 use crate::attr::{HasAttrs, Stability, Deprecation};
 use crate::source_map::SourceMap;
 use crate::edition::Edition;
@@ -671,13 +671,13 @@ bitflags::bitflags! {
 }
 
 pub trait Resolver {
-    fn next_node_id(&mut self) -> ast::NodeId;
+    fn next_node_id(&mut self) -> NodeId;
 
-    fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId;
+    fn get_module_scope(&mut self, id: NodeId) -> ExpnId;
 
     fn resolve_dollar_crates(&mut self);
     fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
-                                            derives: &[ExpnId]);
+                                            extra_placeholders: &[NodeId]);
     fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
 
     fn resolve_imports(&mut self);
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index dac402921b9..c1d52c97455 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -291,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         // Unresolved macros produce dummy outputs as a recovery measure.
         invocations.reverse();
         let mut expanded_fragments = Vec::new();
-        let mut derives: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
+        let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
         let mut undetermined_invocations = Vec::new();
         let (mut progress, mut force) = (false, !self.monotonic);
         loop {
@@ -347,13 +347,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
                 let mut item = self.fully_configure(item);
                 item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
-                let derives = derives.entry(invoc.expansion_data.id).or_default();
+                let derive_placeholders =
+                    all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
 
-                derives.reserve(traits.len());
+                derive_placeholders.reserve(traits.len());
                 invocations.reserve(traits.len());
                 for path in traits {
                     let expn_id = ExpnId::fresh(None);
-                    derives.push(expn_id);
+                    derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
                     invocations.push(Invocation {
                         kind: InvocationKind::Derive { path, item: item.clone() },
                         fragment_kind: invoc.fragment_kind,
@@ -365,7 +366,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 let fragment = invoc.fragment_kind
                     .expect_from_annotatables(::std::iter::once(item));
-                self.collect_invocations(fragment, derives)
+                self.collect_invocations(fragment, derive_placeholders)
             } else {
                 unreachable!()
             };
@@ -384,10 +385,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         // Finally incorporate all the expanded macros into the input AST fragment.
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expanded_fragments) = expanded_fragments.pop() {
-            for (mark, expanded_fragment) in expanded_fragments.into_iter().rev() {
-                let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
-                placeholder_expander.add(NodeId::placeholder_from_expn_id(mark),
-                                         expanded_fragment, derives);
+            for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
+                let derive_placeholders =
+                    all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
+                placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
+                                         expanded_fragment, derive_placeholders);
             }
         }
         fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
@@ -404,7 +406,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     /// them with "placeholders" - dummy macro invocations with specially crafted `NodeId`s.
     /// Then call into resolver that builds a skeleton ("reduced graph") of the fragment and
     /// prepares data for resolving paths of macro invocations.
-    fn collect_invocations(&mut self, mut fragment: AstFragment, derives: &[ExpnId])
+    fn collect_invocations(&mut self, mut fragment: AstFragment, extra_placeholders: &[NodeId])
                            -> (AstFragment, Vec<Invocation>) {
         // Resolve `$crate`s in the fragment for pretty-printing.
         self.cx.resolver.resolve_dollar_crates();
@@ -423,9 +425,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             collector.invocations
         };
 
+        // FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
         if self.monotonic {
             self.cx.resolver.visit_ast_fragment_with_placeholders(
-                self.cx.current_expansion.id, &fragment, derives);
+                self.cx.current_expansion.id, &fragment, extra_placeholders);
         }
 
         (fragment, invocations)
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 2d05f8f0b00..d800cfedcfb 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -2,7 +2,6 @@ use crate::ast::{self, NodeId};
 use crate::source_map::{DUMMY_SP, dummy_spanned};
 use crate::ext::base::ExtCtxt;
 use crate::ext::expand::{AstFragment, AstFragmentKind};
-use crate::ext::hygiene::ExpnId;
 use crate::tokenstream::TokenStream;
 use crate::mut_visit::*;
 use crate::ptr::P;
@@ -86,11 +85,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
         }
     }
 
-    pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, derives: Vec<ExpnId>) {
+    pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
         fragment.mut_visit_with(self);
         if let AstFragment::Items(mut items) = fragment {
-            for derive in derives {
-                match self.remove(NodeId::placeholder_from_expn_id(derive)) {
+            for placeholder in placeholders {
+                match self.remove(placeholder) {
                     AstFragment::Items(derived_items) => items.extend(derived_items),
                     _ => unreachable!(),
                 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1a87a903156..bbc3ae28225 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -559,6 +559,9 @@ declare_features! (
     // Allows `impl Trait` to be used inside type aliases (RFC 2515).
     (active, type_alias_impl_trait, "1.38.0", Some(63063), None),
 
+    // Allows the use of or-patterns, e.g. `0 | 1`.
+    (active, or_patterns, "1.38.0", Some(54883), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -571,6 +574,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
     sym::impl_trait_in_bindings,
     sym::generic_associated_types,
     sym::const_generics,
+    sym::or_patterns,
     sym::let_chains,
 ];
 
@@ -2443,6 +2447,7 @@ pub fn check_crate(krate: &ast::Crate,
     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");
 
     let visitor = &mut PostExpansionVisitor {
         context: &ctx,
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 18d4a646355..9785f8e2de0 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -1050,7 +1050,6 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
                 vis.visit_span(span);
             };
         }
-        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: _ }) => {
@@ -1058,7 +1057,9 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             vis.visit_expr(e2);
             vis.visit_span(span);
         }
-        PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
+        PatKind::Tuple(elems)
+        | PatKind::Slice(elems)
+        | PatKind::Or(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/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 17629d392cd..bdf468a52bb 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -8,9 +8,7 @@ use syntax_pos::{BytePos, Pos, Span};
 use rustc_lexer::Base;
 use rustc_lexer::unescape;
 
-use std::borrow::Cow;
 use std::char;
-use std::iter;
 use std::convert::TryInto;
 use rustc_data_structures::sync::Lrc;
 use log::debug;
@@ -181,18 +179,7 @@ impl<'a> StringReader<'a> {
                 let string = self.str_from(start);
                 // comments with only more "/"s are not doc comments
                 let tok = if is_doc_comment(string) {
-                    let mut idx = 0;
-                    loop {
-                        idx = match string[idx..].find('\r') {
-                            None => break,
-                            Some(it) => idx + it + 1
-                        };
-                        if string[idx..].chars().next() != Some('\n') {
-                            self.err_span_(start + BytePos(idx as u32 - 1),
-                                            start + BytePos(idx as u32),
-                                            "bare CR not allowed in doc-comment");
-                        }
-                    }
+                    self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment");
                     token::DocComment(Symbol::intern(string))
                 } else {
                     token::Comment
@@ -217,15 +204,10 @@ impl<'a> StringReader<'a> {
                 }
 
                 let tok = if is_doc_comment {
-                    let has_cr = string.contains('\r');
-                    let string = if has_cr {
-                        self.translate_crlf(start,
-                                            string,
-                                            "bare CR not allowed in block doc-comment")
-                    } else {
-                        string.into()
-                    };
-                    token::DocComment(Symbol::intern(&string[..]))
+                    self.forbid_bare_cr(start,
+                                        string,
+                                        "bare CR not allowed in block doc-comment");
+                    token::DocComment(Symbol::intern(string))
                 } else {
                     token::Comment
                 };
@@ -516,49 +498,16 @@ impl<'a> StringReader<'a> {
         &self.src[self.src_index(start)..self.src_index(end)]
     }
 
-    /// Converts CRLF to LF in the given string, raising an error on bare CR.
-    fn translate_crlf<'b>(&self, start: BytePos, s: &'b str, errmsg: &'b str) -> Cow<'b, str> {
-        let mut chars = s.char_indices().peekable();
-        while let Some((i, ch)) = chars.next() {
-            if ch == '\r' {
-                if let Some((lf_idx, '\n')) = chars.peek() {
-                    return translate_crlf_(self, start, s, *lf_idx, chars, errmsg).into();
-                }
-                let pos = start + BytePos(i as u32);
-                let end_pos = start + BytePos((i + ch.len_utf8()) as u32);
-                self.err_span_(pos, end_pos, errmsg);
-            }
-        }
-        return s.into();
-
-        fn translate_crlf_(rdr: &StringReader<'_>,
-                           start: BytePos,
-                           s: &str,
-                           mut j: usize,
-                           mut chars: iter::Peekable<impl Iterator<Item = (usize, char)>>,
-                           errmsg: &str)
-                           -> String {
-            let mut buf = String::with_capacity(s.len());
-            // Skip first CR
-            buf.push_str(&s[.. j - 1]);
-            while let Some((i, ch)) = chars.next() {
-                if ch == '\r' {
-                    if j < i {
-                        buf.push_str(&s[j..i]);
-                    }
-                    let next = i + ch.len_utf8();
-                    j = next;
-                    if chars.peek().map(|(_, ch)| *ch) != Some('\n') {
-                        let pos = start + BytePos(i as u32);
-                        let end_pos = start + BytePos(next as u32);
-                        rdr.err_span_(pos, end_pos, errmsg);
-                    }
-                }
-            }
-            if j < s.len() {
-                buf.push_str(&s[j..]);
-            }
-            buf
+    fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) {
+        let mut idx = 0;
+        loop {
+            idx = match s[idx..].find('\r') {
+                None => break,
+                Some(it) => idx + it + 1
+            };
+            self.err_span_(start + BytePos(idx as u32 - 1),
+                           start + BytePos(idx as u32),
+                           errmsg);
         }
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 9088f929372..b1f3612a839 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -66,6 +66,8 @@ pub struct ParseSess {
     // Places where `yield e?` exprs were used and should be feature gated.
     pub yield_spans: Lock<Vec<Span>>,
     pub injected_crate_name: Once<Symbol>,
+    // Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated.
+    pub or_pattern_spans: Lock<Vec<Span>>,
 }
 
 impl ParseSess {
@@ -96,6 +98,7 @@ impl ParseSess {
             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()),
         }
     }
 
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index c3079d2da0c..fd458aec743 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -14,7 +14,10 @@ use errors::{Applicability, DiagnosticBuilder};
 
 impl<'a> Parser<'a> {
     /// Parses a pattern.
-    pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
+    pub fn parse_pat(
+        &mut self,
+        expected: Option<&'static str>
+    ) -> PResult<'a, P<Pat>> {
         self.parse_pat_with_range_pat(true, expected)
     }
 
@@ -97,6 +100,34 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
+    /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`).
+    fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
+        // Parse the first pattern.
+        let first_pat = self.parse_pat(expected)?;
+
+        // If the next token is not a `|`, this is not an or-pattern and
+        // we should exit here.
+        if !self.check(&token::BinOp(token::Or)) {
+            return Ok(first_pat)
+        }
+
+        let lo = first_pat.span;
+
+        let mut pats = vec![first_pat];
+
+        while self.eat(&token::BinOp(token::Or)) {
+            pats.push(self.parse_pat_with_range_pat(
+                true, expected
+            )?);
+        }
+
+        let or_pattern_span = lo.to(self.prev_span);
+
+        self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span);
+
+        Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
+    }
+
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
@@ -240,7 +271,9 @@ impl<'a> Parser<'a> {
 
     /// Parse a tuple or parenthesis pattern.
     fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
-        let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
+        let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
+            p.parse_pat_with_or(None)
+        })?;
 
         // Here, `(pat,)` is a tuple pattern.
         // For backward compatibility, `(..)` is a tuple pattern as well.
@@ -483,7 +516,7 @@ impl<'a> Parser<'a> {
             err.span_label(self.token.span, msg);
             return Err(err);
         }
-        let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
+        let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?;
         Ok(PatKind::TupleStruct(path, fields))
     }
 
@@ -627,7 +660,7 @@ impl<'a> Parser<'a> {
             // Parsing a pattern of the form "fieldname: pat"
             let fieldname = self.parse_field_name()?;
             self.bump();
-            let pat = self.parse_pat(None)?;
+            let pat = self.parse_pat_with_or(None)?;
             hi = pat.span;
             (pat, fieldname, false)
         } else {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 8a7009828bc..4dc00af4860 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -436,18 +436,30 @@ pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefM
     fn print_ident(&mut self, ident: ast::Ident);
     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
 
-    fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
+    fn strsep<T, F>(&mut self, sep: &'static str, space_before: bool,
+                    b: Breaks, elts: &[T], mut op: F)
         where F: FnMut(&mut Self, &T),
     {
         self.rbox(0, b);
-        let mut first = true;
-        for elt in elts {
-            if first { first = false; } else { self.word_space(","); }
-            op(self, elt);
+        if let Some((first, rest)) = elts.split_first() {
+            op(self, first);
+            for elt in rest {
+                if space_before {
+                    self.space();
+                }
+                self.word_space(sep);
+                op(self, elt);
+            }
         }
         self.end();
     }
 
+    fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
+        where F: FnMut(&mut Self, &T),
+    {
+        self.strsep(",", false, b, elts, op)
+    }
+
     fn maybe_print_comment(&mut self, pos: BytePos) {
         while let Some(ref cmnt) = self.next_comment() {
             if cmnt.pos < pos {
@@ -2353,6 +2365,9 @@ impl<'a> State<'a> {
                 self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
                 self.pclose();
             }
+            PatKind::Or(ref pats) => {
+                self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
+            }
             PatKind::Path(None, ref path) => {
                 self.print_path(path, true, 0);
             }
@@ -2429,16 +2444,7 @@ impl<'a> State<'a> {
     }
 
     fn print_pats(&mut self, pats: &[P<ast::Pat>]) {
-        let mut first = true;
-        for p in pats {
-            if first {
-                first = false;
-            } else {
-                self.s.space();
-                self.word_space("|");
-            }
-            self.print_pat(p);
-        }
+        self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
     }
 
     fn print_arm(&mut self, arm: &ast::Arm) {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 6648347d4ae..91b92d84a81 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -447,9 +447,6 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
                 visitor.visit_pat(&field.pat)
             }
         }
-        PatKind::Tuple(ref elems) => {
-            walk_list!(visitor, visit_pat, elems);
-        }
         PatKind::Box(ref subpattern) |
         PatKind::Ref(ref subpattern, _) |
         PatKind::Paren(ref subpattern) => {
@@ -465,7 +462,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
             visitor.visit_expr(upper_bound);
         }
         PatKind::Wild | PatKind::Rest => {},
-        PatKind::Slice(ref elems) => {
+        PatKind::Tuple(ref elems)
+        | PatKind::Slice(ref elems)
+        | PatKind::Or(ref elems) => {
             walk_list!(visitor, visit_pat, elems);
         }
         PatKind::Mac(ref mac) => visitor.visit_mac(mac),