diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 708e48fe6add1..09a8a603407fd 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -556,7 +556,6 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::impl_trait_in_bindings, sym::generic_associated_types, sym::const_generics, - sym::or_patterns, sym::let_chains, sym::raw_dylib, ]; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index e611c2d504e3f..baf02e9ce5748 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -26,8 +26,9 @@ mod simplify; mod test; mod util; -use itertools::Itertools; +use std::borrow::Borrow; use std::convert::TryFrom; +use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Generates MIR for a `match` expression. @@ -66,12 +67,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// We generate MIR in the following steps: /// /// 1. Evaluate the scrutinee and add the fake read of it ([Builder::lower_scrutinee]). - /// 2. Create the prebinding and otherwise blocks ([Builder::create_match_candidates]). - /// 3. Create the decision tree ([Builder::lower_match_tree]). - /// 4. Determine the fake borrows that are needed from the places that were + /// 2. Create the decision tree ([Builder::lower_match_tree]). + /// 3. Determine the fake borrows that are needed from the places that were /// matched against and create the required temporaries for them /// ([Builder::calculate_fake_borrows]). - /// 5. Create everything else: the guards and the arms ([Builder::lower_match_arms]). + /// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]). /// /// ## False edges /// @@ -96,11 +96,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms); let match_has_guard = arms.iter().any(|arm| arm.guard.is_some()); - let candidates = - arm_candidates.iter_mut().flat_map(|(_, candidates)| candidates).collect::>(); + let mut candidates = + arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::>(); let fake_borrow_temps = - self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates); + self.lower_match_tree(block, scrutinee_span, match_has_guard, &mut candidates); self.lower_match_arms( &destination, @@ -147,40 +147,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, scrutinee: &Place<'tcx>, arms: &'pat [Arm<'tcx>], - ) -> Vec<(&'pat Arm<'tcx>, Vec>)> { - let candidate_count = arms.iter().map(|c| c.top_pats_hack().len()).sum::(); - let pre_binding_blocks: Vec<_> = - (0..candidate_count).map(|_| self.cfg.start_new_block()).collect(); - - let mut candidate_pre_binding_blocks = pre_binding_blocks.iter(); - let mut next_candidate_pre_binding_blocks = pre_binding_blocks.iter().skip(1); - + ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> { // Assemble a list of candidates: there is one candidate per pattern, // which means there may be more than one candidate *per arm*. arms.iter() .map(|arm| { let arm_has_guard = arm.guard.is_some(); - let arm_candidates: Vec<_> = arm - .top_pats_hack() - .iter() - .zip(candidate_pre_binding_blocks.by_ref()) - .map(|(pattern, pre_binding_block)| Candidate { - span: pattern.span, - match_pairs: smallvec![MatchPair::new(scrutinee.clone(), pattern)], - bindings: vec![], - ascriptions: vec![], - otherwise_block: if arm_has_guard { - Some(self.cfg.start_new_block()) - } else { - None - }, - pre_binding_block: *pre_binding_block, - next_candidate_pre_binding_block: next_candidate_pre_binding_blocks - .next() - .copied(), - }) - .collect(); - (arm, arm_candidates) + let arm_candidate = Candidate { + span: arm.pattern.span, + match_pairs: smallvec![MatchPair::new(scrutinee.clone(), &arm.pattern),], + bindings: vec![], + ascriptions: vec![], + has_guard: arm_has_guard, + needs_otherwise_block: arm_has_guard, + otherwise_block: None, + pre_binding_block: None, + next_candidate_pre_binding_block: None, + subcandidates: vec![], + }; + (arm, arm_candidate) }) .collect() } @@ -196,22 +181,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, scrutinee_span: Span, match_has_guard: bool, - mut candidates: Vec<&mut Candidate<'pat, 'tcx>>, + candidates: &mut [&mut Candidate<'pat, 'tcx>], ) -> Vec<(Place<'tcx>, Local)> { // The set of places that we are creating fake borrows of. If there are // no match guards then we don't need any fake borrows, so don't track // them. let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None }; + let mut otherwise = None; + // This will generate code to test scrutinee_place and // branch to the appropriate arm block - self.match_candidates( - scrutinee_span, - &mut Some(block), - None, - &mut candidates, - &mut fake_borrows, - ); + self.match_candidates(scrutinee_span, block, &mut otherwise, candidates, &mut fake_borrows); + + if let Some(otherwise_block) = otherwise { + let source_info = self.source_info(scrutinee_span); + self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); + } + + let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; + + for candidate in candidates { + candidate.visit_leaves(|leaf_candidate| { + if let Some(ref mut prev) = previous_candidate { + prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block; + } + previous_candidate = Some(leaf_candidate); + }); + } if let Some(ref borrows) = fake_borrows { self.calculate_fake_borrows(borrows, scrutinee_span) @@ -231,7 +228,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: &Place<'tcx>, scrutinee_place: Place<'tcx>, scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Vec>)>, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local)>, ) -> BlockAnd<()> { @@ -239,8 +236,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_end_blocks: Vec<_> = arm_candidates .into_iter() - .map(|(arm, candidates)| { - debug!("lowering arm {:?}\ncanidates = {:?}", arm, candidates); + .map(|(arm, candidate)| { + debug!("lowering arm {:?}\ncanidate = {:?}", arm, candidate); let arm_source_info = self.source_info(arm.span); let arm_scope = (arm.scope, arm_source_info); @@ -249,18 +246,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = this.declare_bindings( None, arm.span, - &arm.top_pats_hack()[0], + &arm.pattern, ArmHasGuard(arm.guard.is_some()), Some((Some(&scrutinee_place), scrutinee_span)), ); let arm_block = this.bind_pattern( outer_source_info, - candidates, + candidate, arm.guard.as_ref().map(|g| (g, match_scope)), &fake_borrow_temps, scrutinee_span, - arm.scope, + Some(arm.scope), ); if let Some(source_scope) = scope { @@ -290,35 +287,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_pattern( &mut self, outer_source_info: SourceInfo, - mut candidates: Vec>, + candidate: Candidate<'_, 'tcx>, guard: Option<(&Guard<'tcx>, region::Scope)>, fake_borrow_temps: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, - arm_scope: region::Scope, + arm_scope: Option, ) -> BasicBlock { - if candidates.len() == 1 { + if candidate.subcandidates.is_empty() { // Avoid generating another `BasicBlock` when we only have one // candidate. self.bind_and_guard_matched_candidate( - candidates.pop().unwrap(), + candidate, + &[], guard, fake_borrow_temps, scrutinee_span, + true, ) } else { - let arm_block = self.cfg.start_new_block(); - for candidate in candidates { - // Avoid scheduling drops multiple times. - self.clear_top_scope(arm_scope); - let binding_end = self.bind_and_guard_matched_candidate( - candidate, - guard, - fake_borrow_temps, - scrutinee_span, - ); - self.cfg.goto(binding_end, outer_source_info, arm_block); - } - arm_block + let target_block = self.cfg.start_new_block(); + let mut schedule_drops = true; + // We keep a stack of all of the bindings and type asciptions + // from the the parent candidates that we visit, that also need to + // be bound for each candidate. + traverse_candidate( + candidate, + &mut Vec::new(), + &mut |leaf_candidate, parent_bindings| { + if let Some(arm_scope) = arm_scope { + // Avoid scheduling drops multiple times by unscheduling drops. + self.clear_top_scope(arm_scope); + } + let binding_end = self.bind_and_guard_matched_candidate( + leaf_candidate, + parent_bindings, + guard, + &fake_borrow_temps, + scrutinee_span, + schedule_drops, + ); + if arm_scope.is_none() { + // If we aren't in a match, then our bindings may not be + // the only thing in the top scope, so only schedule + // them to drop for the first pattern instead. + schedule_drops = false; + } + self.cfg.goto(binding_end, outer_source_info, target_block); + }, + |inner_candidate, parent_bindings| { + parent_bindings.push((inner_candidate.bindings, inner_candidate.ascriptions)); + inner_candidate.subcandidates.into_iter() + }, + |parent_bindings| { + parent_bindings.pop(); + }, + ); + + target_block } } @@ -427,61 +452,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // create a dummy candidate let mut candidate = Candidate { span: irrefutable_pat.span, + has_guard: false, + needs_otherwise_block: false, match_pairs: smallvec![MatchPair::new(initializer.clone(), &irrefutable_pat)], bindings: vec![], ascriptions: vec![], // since we don't call `match_candidates`, next fields are unused otherwise_block: None, - pre_binding_block: block, + pre_binding_block: None, next_candidate_pre_binding_block: None, + subcandidates: vec![], }; - // Simplify the candidate. Since the pattern is irrefutable, this should - // always convert all match-pairs into bindings. - self.simplify_candidate(&mut candidate); - - if !candidate.match_pairs.is_empty() { - // ICE if no other errors have been emitted. This used to be a hard error that wouldn't - // be reached because `hair::pattern::check_match::check_match` wouldn't have let the - // compiler continue. In our tests this is only ever hit by - // `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates - // a different error before hand. - self.hir.tcx().sess.delay_span_bug( - candidate.match_pairs[0].pattern.span, - &format!( - "match pairs {:?} remaining after simplifying irrefutable pattern", - candidate.match_pairs, - ), - ); - } + let fake_borrow_temps = + self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]); // for matches and function arguments, the place that is being matched // can be set when creating the variables. But the place for // let PATTERN = ... might not even exist until we do the assignment. // so we set it here instead if set_match_place { - for binding in &candidate.bindings { - let local = self.var_local_id(binding.var_id, OutsideGuard); - - if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref mut match_place, _)), - .. - }))) = self.local_decls[local].local_info - { - *match_place = Some(initializer.clone()); - } else { - bug!("Let binding to non-user variable.") + let mut candidate_ref = &candidate; + while let Some(next) = { + for binding in &candidate_ref.bindings { + let local = self.var_local_id(binding.var_id, OutsideGuard); + + if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, + ))) = self.local_decls[local].local_info + { + *match_place = Some(initializer.clone()); + } else { + bug!("Let binding to non-user variable.") + } } + candidate_ref.subcandidates.get(0) + } { + candidate_ref = next; } } - self.ascribe_types(block, &candidate.ascriptions); - - // now apply the bindings, which will also declare the variables - self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); - - block.unit() + self.bind_pattern( + self.source_info(irrefutable_pat.span), + candidate, + None, + &fake_borrow_temps, + irrefutable_pat.span, + None, + ) + .unit() } /// Declares the bindings of the given patterns and returns the visibility @@ -632,9 +652,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } PatKind::Or { ref pats } => { - for pat in pats { - self.visit_bindings(&pat, pattern_user_ty.clone(), f); - } + self.visit_bindings(&pats[0], pattern_user_ty.clone(), f); } } } @@ -642,26 +660,72 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { #[derive(Debug)] pub struct Candidate<'pat, 'tcx> { - // span of the original pattern that gave rise to this candidate + /// `Span` of the original pattern that gave rise to this candidate span: Span, - // all of these must be satisfied... + /// This `Candidate` has a guard. + has_guard: bool, + + /// This `Candidate` needs and otherwise block, either because it has a + /// guard or it has subcandidates. + needs_otherwise_block: bool, + + /// All of these must be satisfied... match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>, - // ...these bindings established... + /// ...these bindings established... bindings: Vec>, - // ...and these types asserted... + /// ...and these types asserted... ascriptions: Vec>, - // ...and the guard must be evaluated, if false branch to Block... + /// ... and if this is non-empty, one of these subcandidates also has to match ... + subcandidates: Vec>, + + /// ...and the guard must be evaluated, if false branch to Block... otherwise_block: Option, - // ...and the blocks for add false edges between candidates - pre_binding_block: BasicBlock, + /// ...and the blocks for add false edges between candidates + pre_binding_block: Option, next_candidate_pre_binding_block: Option, } +impl Candidate<'_, '_> { + /// Visit the leaf candidates (those with no subcandidates) contained in + /// this candidate. + fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) { + traverse_candidate( + self, + &mut (), + &mut move |c, _| visit_leaf(c), + move |c, _| c.subcandidates.iter_mut(), + |_| {}, + ); + } +} + +/// A depth-first traversal of the `Candidate` and all of its recursive +/// subcandidates. +fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>( + candidate: C, + context: &mut T, + visit_leaf: &mut impl FnMut(C, &mut T), + get_children: impl Copy + Fn(C, &mut T) -> I, + complete_children: impl Copy + Fn(&mut T), +) where + C: Borrow>, + I: Iterator, +{ + if candidate.borrow().subcandidates.is_empty() { + visit_leaf(candidate, context) + } else { + for child in get_children(candidate, context) { + traverse_candidate(child, context, visit_leaf, get_children, complete_children); + } + complete_children(context) + } +} + #[derive(Clone, Debug)] struct Binding<'tcx> { span: Span, @@ -758,13 +822,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// which of these candidates, if any, is the correct one. The /// candidates are sorted such that the first item in the list /// has the highest priority. When a candidate is found to match - /// the value, we will generate a branch to the appropriate + /// the value, we will set and generate a branch to the appropriate /// prebinding block. /// /// If we find that *NONE* of the candidates apply, we branch to the - /// `otherwise_block`. In principle, this means that the input list was not - /// exhaustive, though at present we sometimes are not smart enough to - /// recognize all exhaustive inputs. + /// `otherwise_block`, setting it to `Some` if required. In principle, this + /// means that the input list was not exhaustive, though at present we + /// sometimes are not smart enough to recognize all exhaustive inputs. /// /// It might be surprising that the input can be inexhaustive. /// Indeed, initially, it is not, because all matches are @@ -778,8 +842,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn match_candidates<'pat>( &mut self, span: Span, - start_block: &mut Option, - otherwise_block: Option, + start_block: BasicBlock, + otherwise_block: &mut Option, candidates: &mut [&mut Candidate<'pat, 'tcx>], fake_borrows: &mut Option>>, ) { @@ -791,10 +855,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Start by simplifying candidates. Once this process is complete, all // the match pairs which remain require some form of test, whether it // be a switch or pattern comparison. + let mut split_or_candidate = false; for candidate in &mut *candidates { - self.simplify_candidate(candidate); + split_or_candidate |= self.simplify_candidate(candidate); } + if split_or_candidate { + // At least one of the candidates has been split into subcandidates. + // We need to change the candidate list to include those. + let mut new_candidates = Vec::new(); + + for candidate in candidates { + candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate)); + } + self.match_simplified_candidates( + span, + start_block, + otherwise_block, + &mut *new_candidates, + fake_borrows, + ); + } else { + self.match_simplified_candidates( + span, + start_block, + otherwise_block, + candidates, + fake_borrows, + ); + }; + } + + fn match_simplified_candidates( + &mut self, + span: Span, + start_block: BasicBlock, + otherwise_block: &mut Option, + candidates: &mut [&mut Candidate<'pat, 'tcx>], + fake_borrows: &mut Option>>, + ) { // The candidates are sorted by priority. Check to see whether the // higher priority candidates (and hence at the front of the slice) // have satisfied all their match pairs. @@ -802,7 +901,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("match_candidates: {:?} candidates fully matched", fully_matched); let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched); - let block: BasicBlock = if !matched_candidates.is_empty() { + let block = if !matched_candidates.is_empty() { let otherwise_block = self.select_matched_candidates(matched_candidates, start_block, fake_borrows); @@ -816,7 +915,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.start_new_block() } } else { - *start_block.get_or_insert_with(|| self.cfg.start_new_block()) + start_block }; // If there are no candidates that still need testing, we're @@ -824,15 +923,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // never reach this point. if unmatched_candidates.is_empty() { let source_info = self.source_info(span); - match otherwise_block { - Some(otherwise) => self.cfg.goto(block, source_info, otherwise), - None => self.cfg.terminate(block, source_info, TerminatorKind::Unreachable), + if let Some(otherwise) = *otherwise_block { + self.cfg.goto(block, source_info, otherwise); + } else { + *otherwise_block = Some(block); } return; } // Test for the remaining candidates. - self.test_candidates(span, unmatched_candidates, block, otherwise_block, fake_borrows); + self.test_candidates_with_or( + span, + unmatched_candidates, + block, + otherwise_block, + fake_borrows, + ); } /// Link up matched candidates. For example, if we have something like @@ -856,13 +962,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn select_matched_candidates( &mut self, matched_candidates: &mut [&mut Candidate<'_, 'tcx>], - start_block: &mut Option, + start_block: BasicBlock, fake_borrows: &mut Option>>, ) -> Option { debug_assert!( !matched_candidates.is_empty(), "select_matched_candidates called with no candidates", ); + debug_assert!( + matched_candidates.iter().all(|c| c.subcandidates.is_empty()), + "subcandidates should be empty in select_matched_candidates", + ); // Insert a borrows of prefixes of places that are bound and are // behind a dereference projection. @@ -899,65 +1009,147 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fully_matched_with_guard = matched_candidates .iter() - .position(|c| c.otherwise_block.is_none()) + .position(|c| !c.needs_otherwise_block) .unwrap_or(matched_candidates.len() - 1); let (reachable_candidates, unreachable_candidates) = matched_candidates.split_at_mut(fully_matched_with_guard + 1); - let first_candidate = &reachable_candidates[0]; - let first_prebinding_block = first_candidate.pre_binding_block; + let mut next_prebinding = start_block; - // `goto -> first_prebinding_block` from the `start_block` if there is one. - if let Some(start_block) = *start_block { - let source_info = self.source_info(first_candidate.span); - self.cfg.goto(start_block, source_info, first_prebinding_block); - } else { - *start_block = Some(first_prebinding_block); - } - - for (first_candidate, second_candidate) in reachable_candidates.iter().tuple_windows() { - let source_info = self.source_info(first_candidate.span); - if let Some(otherwise_block) = first_candidate.otherwise_block { - self.false_edges( - otherwise_block, - second_candidate.pre_binding_block, - first_candidate.next_candidate_pre_binding_block, - source_info, - ); - } else { - bug!("candidate other than the last has no guard"); + for candidate in reachable_candidates.iter_mut() { + assert!(candidate.otherwise_block.is_none()); + assert!(candidate.pre_binding_block.is_none()); + candidate.pre_binding_block = Some(next_prebinding); + if candidate.needs_otherwise_block { + next_prebinding = self.cfg.start_new_block(); + candidate.otherwise_block = Some(next_prebinding); } } - debug!("match_candidates: add false edges for unreachable {:?}", unreachable_candidates); + debug!( + "match_candidates: add pre_binding_blocks for unreachable {:?}", + unreachable_candidates, + ); for candidate in unreachable_candidates { - if let Some(otherwise) = candidate.otherwise_block { - let source_info = self.source_info(candidate.span); - let unreachable = self.cfg.start_new_block(); - self.false_edges( - otherwise, - unreachable, - candidate.next_candidate_pre_binding_block, - source_info, - ); - self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable); - } + assert!(candidate.pre_binding_block.is_none()); + candidate.pre_binding_block = Some(self.cfg.start_new_block()); } - let last_candidate = reachable_candidates.last().unwrap(); - if let Some(otherwise) = last_candidate.otherwise_block { - let source_info = self.source_info(last_candidate.span); - let block = self.cfg.start_new_block(); - self.false_edges( - otherwise, - block, - last_candidate.next_candidate_pre_binding_block, - source_info, - ); - Some(block) + reachable_candidates.last_mut().unwrap().otherwise_block + } + + fn test_candidates_with_or( + &mut self, + span: Span, + candidates: &mut [&mut Candidate<'_, 'tcx>], + block: BasicBlock, + otherwise_block: &mut Option, + fake_borrows: &mut Option>>, + ) { + let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap(); + + if let PatKind::Or { .. } = *first_candidate.match_pairs[0].pattern.kind { + let match_pairs = mem::take(&mut first_candidate.match_pairs); + first_candidate.needs_otherwise_block = true; + first_candidate.pre_binding_block = Some(block); + + // We sort or-patterns to the end in `simplify_candidate`, so all + // the remaining match pairs are or-patterns. + for match_pair in match_pairs { + if let PatKind::Or { ref pats } = *match_pair.pattern.kind { + let or_span = match_pair.pattern.span; + let place = &match_pair.place; + + first_candidate.visit_leaves(|leaf_candidate| { + self.test_or_pattern(leaf_candidate, pats, or_span, place, fake_borrows); + }); + } else { + bug!("Or patterns should have been sorted to the end"); + } + } + let remainder_start = + first_candidate.otherwise_block.unwrap_or_else(|| self.cfg.start_new_block()); + self.match_candidates( + span, + remainder_start, + otherwise_block, + remaining_candidates, + fake_borrows, + ) } else { - None + self.test_candidates(span, candidates, block, otherwise_block, fake_borrows) + } + } + + fn test_or_pattern<'pat>( + &mut self, + candidate: &mut Candidate<'pat, 'tcx>, + pats: &'pat [Pat<'tcx>], + or_span: Span, + place: &Place<'tcx>, + fake_borrows: &mut Option>>, + ) { + debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats); + let mut or_candidates: Vec<_> = pats + .iter() + .map(|pat| { + let new_match_pair = smallvec![MatchPair { pattern: pat, place: place.clone() }]; + Candidate { + span: pat.span, + has_guard: candidate.has_guard, + needs_otherwise_block: candidate.needs_otherwise_block, + match_pairs: new_match_pair, + bindings: Vec::new(), + ascriptions: Vec::new(), + otherwise_block: None, + pre_binding_block: None, + next_candidate_pre_binding_block: None, + subcandidates: Vec::new(), + } + }) + .collect(); + let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect(); + self.match_candidates( + or_span, + candidate.pre_binding_block.unwrap(), + &mut candidate.otherwise_block, + &mut or_candidate_refs, + fake_borrows, + ); + candidate.subcandidates = or_candidates; + self.merge_trivial_subcandidates(candidate, self.source_info(or_span)); + } + + /// Try to merge all of the subcandidates of the given candidate into one. + /// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. + fn merge_trivial_subcandidates( + &mut self, + candidate: &mut Candidate<'pat, 'tcx>, + source_info: SourceInfo, + ) { + if candidate.subcandidates.is_empty() { + return; + } + let mut can_merge = !candidate.has_guard; + + // Not `Iterator::all` because we don't want to short-circuit. + for subcandidate in &mut candidate.subcandidates { + self.merge_trivial_subcandidates(subcandidate, source_info); + + // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. + can_merge &= subcandidate.subcandidates.is_empty() + && subcandidate.bindings.is_empty() + && subcandidate.ascriptions.is_empty(); + } + + if can_merge { + let any_matches = self.cfg.start_new_block(); + for subcandidate in mem::take(&mut candidate.subcandidates) { + let or_block = subcandidate.pre_binding_block.unwrap(); + self.cfg.goto(or_block, source_info, any_matches); + } + candidate.pre_binding_block = Some(any_matches); } } @@ -1078,7 +1270,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], block: BasicBlock, - mut otherwise_block: Option, + otherwise_block: &mut Option, fake_borrows: &mut Option>>, ) { // extract the match-pair from the highest priority candidate @@ -1150,49 +1342,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // improves the speed of llvm when optimizing long string literal // matches let make_target_blocks = move |this: &mut Self| -> Vec { + // The block that we should branch to if none of the + // `target_candidates` match. This is either the block where we + // start matching the untested candidates if there are any, + // otherwise it's the `otherwise_block`. + let remainder_start = &mut None; + let remainder_start = + if candidates.is_empty() { &mut *otherwise_block } else { remainder_start }; + // For each outcome of test, process the candidates that still // apply. Collect a list of blocks where control flow will // branch if one of the `target_candidate` sets is not // exhaustive. - if !candidates.is_empty() { - let remainder_start = &mut None; - this.match_candidates( - span, - remainder_start, - otherwise_block, - candidates, - fake_borrows, - ); - otherwise_block = Some(remainder_start.unwrap()); - }; - - target_candidates + let target_blocks: Vec<_> = target_candidates .into_iter() .map(|mut candidates| { if candidates.len() != 0 { - let candidate_start = &mut None; + let candidate_start = this.cfg.start_new_block(); this.match_candidates( span, candidate_start, - otherwise_block, + remainder_start, &mut *candidates, fake_borrows, ); - candidate_start.unwrap() + candidate_start } else { - *otherwise_block.get_or_insert_with(|| { - let unreachable = this.cfg.start_new_block(); - let source_info = this.source_info(span); - this.cfg.terminate( - unreachable, - source_info, - TerminatorKind::Unreachable, - ); - unreachable - }) + *remainder_start.get_or_insert_with(|| this.cfg.start_new_block()) } }) - .collect() + .collect(); + + if !candidates.is_empty() { + let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block()); + this.match_candidates( + span, + remainder_start, + otherwise_block, + candidates, + fake_borrows, + ); + }; + + target_blocks }; self.perform_test(block, &match_place, &test, make_target_blocks); @@ -1287,9 +1479,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_and_guard_matched_candidate<'pat>( &mut self, candidate: Candidate<'pat, 'tcx>, + parent_bindings: &[(Vec>, Vec>)], guard: Option<(&Guard<'tcx>, region::Scope)>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, + schedule_drops: bool, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1297,15 +1491,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let candidate_source_info = self.source_info(candidate.span); - let mut block = candidate.pre_binding_block; - - // If we are adding our own statements, then we need a fresh block. - let create_fresh_block = candidate.next_candidate_pre_binding_block.is_some() - || !candidate.bindings.is_empty() - || !candidate.ascriptions.is_empty() - || guard.is_some(); + let mut block = candidate.pre_binding_block.unwrap(); - if create_fresh_block { + if candidate.next_candidate_pre_binding_block.is_some() { let fresh_block = self.cfg.start_new_block(); self.false_edges( block, @@ -1314,11 +1502,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate_source_info, ); block = fresh_block; - self.ascribe_types(block, &candidate.ascriptions); - } else { - return block; } + self.ascribe_types( + block, + parent_bindings + .iter() + .flat_map(|(_, ascriptions)| ascriptions) + .chain(&candidate.ascriptions), + ); + // rust-lang/rust#27282: The `autoref` business deserves some // explanation here. // @@ -1401,14 +1594,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // reference to that. if let Some((guard, region_scope)) = guard { let tcx = self.hir.tcx(); + let bindings = parent_bindings + .iter() + .flat_map(|(bindings, _)| bindings) + .chain(&candidate.bindings); - self.bind_matched_candidate_for_guard(block, &candidate.bindings); + self.bind_matched_candidate_for_guard(block, bindings.clone()); let guard_frame = GuardFrame { - locals: candidate - .bindings - .iter() - .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) - .collect(), + locals: bindings.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)).collect(), }; debug!("entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); @@ -1437,11 +1630,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp)); } + let otherwise_block = candidate.otherwise_block.unwrap_or_else(|| { + let unreachable = self.cfg.start_new_block(); + self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable); + unreachable + }); + let outside_scope = self.cfg.start_new_block(); self.exit_scope( source_info.span, region_scope, otherwise_post_guard_block, - candidate.otherwise_block.unwrap(), + outside_scope, + ); + self.false_edges( + outside_scope, + otherwise_block, + candidate.next_candidate_pre_binding_block, + source_info, ); // We want to ensure that the matched candidates are bound @@ -1470,9 +1675,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = candidate.bindings.iter().filter(|binding| { - if let BindingMode::ByValue = binding.binding_mode { true } else { false } - }); + let by_value_bindings = + parent_bindings + .iter() + .flat_map(|(bindings, _)| bindings) + .chain(&candidate.bindings) + .filter(|binding| { + if let BindingMode::ByValue = binding.binding_mode { true } else { false } + }); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -1480,22 +1690,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause = FakeReadCause::ForGuardBinding; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } - self.bind_matched_candidate_for_arm_body(post_guard_block, by_value_bindings); + assert!(schedule_drops, "patterns with guards must schedule drops"); + self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings); post_guard_block } else { - assert!(candidate.otherwise_block.is_none()); // (Here, it is not too early to bind the matched // candidate on `block`, because there is no guard result // that we have to inspect before we bind them.) - self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); + self.bind_matched_candidate_for_arm_body( + block, + schedule_drops, + parent_bindings + .iter() + .flat_map(|(bindings, _)| bindings) + .chain(&candidate.bindings), + ); block } } /// Append `AscribeUserType` statements onto the end of `block` /// for each ascription - fn ascribe_types(&mut self, block: BasicBlock, ascriptions: &[Ascription<'tcx>]) { + fn ascribe_types<'b>( + &mut self, + block: BasicBlock, + ascriptions: impl IntoIterator>, + ) where + 'tcx: 'b, + { for ascription in ascriptions { let source_info = self.source_info(ascription.span); @@ -1522,14 +1745,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - fn bind_matched_candidate_for_guard(&mut self, block: BasicBlock, bindings: &[Binding<'tcx>]) { - debug!("bind_matched_candidate_for_guard(block={:?}, bindings={:?})", block, bindings); + fn bind_matched_candidate_for_guard<'b>( + &mut self, + block: BasicBlock, + bindings: impl IntoIterator>, + ) where + 'tcx: 'b, + { + debug!("bind_matched_candidate_for_guard(block={:?})", block); // Assign each of the bindings. Since we are binding for a // guard expression, this will never trigger moves out of the // candidate. let re_erased = self.hir.tcx().lifetimes.re_erased; for binding in bindings { + debug!("bind_matched_candidate_for_guard(binding={:?})", binding); let source_info = self.source_info(binding.span); // For each pattern ident P of type T, `ref_for_guard` is @@ -1563,6 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_arm_body<'b>( &mut self, block: BasicBlock, + schedule_drops: bool, bindings: impl IntoIterator>, ) where 'tcx: 'b, @@ -1575,7 +1806,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(binding.span); let local = self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard); - self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); + if schedule_drops { + self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); + } let rvalue = match binding.binding_mode { BindingMode::ByValue => { Rvalue::Use(self.consume_by_copy_or_move(binding.source.clone())) diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index bbb555a58e69f..4ace3d59a0281 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -17,17 +17,39 @@ use crate::build::Builder; use crate::hair::{self, *}; use rustc::hir::RangeEnd; use rustc::mir::interpret::truncate; +use rustc::mir::Place; use rustc::ty; use rustc::ty::layout::{Integer, IntegerExt, Size}; use syntax::attr::{SignedInt, UnsignedInt}; +use smallvec::smallvec; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { - pub fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) { + /// Simplify a candidate so that all match pairs require a test. + /// + /// This method will also split a candidate where the only match-pair is an + /// or-pattern into multiple candidates. This is so that + /// + /// match x { + /// 0 | 1 => { ... }, + /// 2 | 3 => { ... }, + /// } + /// + /// only generates a single switch. If this happens this method returns + /// `true`. + pub fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) -> bool { // repeatedly simplify match pairs until fixed point is reached loop { let match_pairs = mem::take(&mut candidate.match_pairs); + + if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, ref place }] = + *match_pairs + { + candidate.subcandidates = self.create_or_subcanidates(candidate, place, pats); + return true; + } + let mut changed = false; for match_pair in match_pairs { match self.simplify_match_pair(match_pair, candidate) { @@ -40,11 +62,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } if !changed { - return; // if we were not able to simplify any, done. + // Move or-patterns to the end, because they can result in us + // creating additional candidates, so we want to test them as + // late as possible. + candidate + .match_pairs + .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. })); + return false; // if we were not able to simplify any, done. } } } + fn create_or_subcanidates<'pat>( + &mut self, + candidate: &Candidate<'pat, 'tcx>, + place: &Place<'tcx>, + pats: &'pat [Pat<'tcx>], + ) -> Vec> { + pats.iter() + .map(|pat| { + let mut candidate = Candidate { + span: pat.span, + has_guard: candidate.has_guard, + needs_otherwise_block: candidate.needs_otherwise_block, + match_pairs: smallvec![MatchPair { place: place.clone(), pattern: pat }], + bindings: vec![], + ascriptions: vec![], + subcandidates: vec![], + otherwise_block: None, + pre_binding_block: None, + next_candidate_pre_binding_block: None, + }; + self.simplify_candidate(&mut candidate); + candidate + }) + .collect() + } + /// Tries to simplify `match_pair`, returning `Ok(())` if /// successful. If successful, new match pairs and bindings will /// have been pushed into the candidate. If no simplification is diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index cdb27099c28f4..1f5f628479550 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -70,11 +70,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatKind::Or { .. } => self - .hir - .tcx() - .sess - .span_fatal(match_pair.pattern.span, "or-patterns are not fully implemented yet"), + PatKind::Or { .. } => bug!("or-patterns should have already been handled"), PatKind::AscribeUserType { .. } | PatKind::Array { .. } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 8973c19d58f63..96a1e25f6ec13 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -315,17 +315,6 @@ pub struct Arm<'tcx> { pub span: Span, } -impl Arm<'tcx> { - // HACK(or_patterns; Centril | dlrobertson): Remove this and - // correctly handle each case in which this method is used. - pub fn top_pats_hack(&self) -> &[Pat<'tcx>] { - match &*self.pattern.kind { - PatKind::Or { pats } => pats, - _ => std::slice::from_ref(&self.pattern), - } - } -} - #[derive(Clone, Debug)] pub enum Guard<'tcx> { If(ExprRef<'tcx>), diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs index 07bbd9202b940..667d21fc14ee4 100644 --- a/src/test/mir-opt/const_prop/discriminant.rs +++ b/src/test/mir-opt/const_prop/discriminant.rs @@ -10,18 +10,18 @@ fn main() { // ... // _3 = std::option::Option::::Some(const true,); // _4 = discriminant(_3); -// switchInt(move _4) -> [1isize: bb3, otherwise: bb2]; +// switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // } // bb1: { -// _2 = const 42i32; +// _2 = const 10i32; // goto -> bb4; // } // bb2: { -// _2 = const 10i32; -// goto -> bb4; +// switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // } // bb3: { -// switchInt(((_3 as Some).0: bool)) -> [false: bb2, otherwise: bb1]; +// _2 = const 42i32; +// goto -> bb4; // } // bb4: { // _1 = Add(move _2, const 0i32); @@ -33,18 +33,18 @@ fn main() { // ... // _3 = const Scalar(0x01) : std::option::Option; // _4 = const 1isize; -// switchInt(const 1isize) -> [1isize: bb3, otherwise: bb2]; +// switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // } // bb1: { -// _2 = const 42i32; +// _2 = const 10i32; // goto -> bb4; // } // bb2: { -// _2 = const 10i32; -// goto -> bb4; +// switchInt(const true) -> [false: bb1, otherwise: bb3]; // } // bb3: { -// switchInt(const true) -> [false: bb2, otherwise: bb1]; +// _2 = const 42i32; +// goto -> bb4; // } // bb4: { // _1 = Add(move _2, const 0i32); diff --git a/src/test/mir-opt/exponential-or.rs b/src/test/mir-opt/exponential-or.rs new file mode 100644 index 0000000000000..832a7b48dc01c --- /dev/null +++ b/src/test/mir-opt/exponential-or.rs @@ -0,0 +1,79 @@ +// Test that simple or-patterns don't get expanded to exponentially large CFGs + +// ignore-tidy-linelength + +#![feature(or_patterns)] + +fn match_tuple(x: (u32, bool, Option, u32)) -> u32 { + match x { + (y @ (1 | 4), true | false, Some(1 | 8) | None, z @ (6..=9 | 13..=16)) => y + 2 * z, + _ => 0, + } +} + +fn main() {} + +// END RUST SOURCE + +// START rustc.match_tuple.SimplifyCfg-initial.after.mir +// scope 1 { +// debug y => _7; +// debug z => _8; +// } +// bb0: { +// FakeRead(ForMatchedPlace, _1); +// switchInt((_1.0: u32)) -> [1u32: bb2, 4u32: bb2, otherwise: bb1]; +// } +// bb1: { +// _0 = const 0u32; +// goto -> bb10; +// } +// bb2: { +// _2 = discriminant((_1.2: std::option::Option)); +// switchInt(move _2) -> [0isize: bb4, 1isize: bb3, otherwise: bb1]; +// } +// bb3: { +// switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1i32: bb4, 8i32: bb4, otherwise: bb1]; +// } +// bb4: { +// _5 = Le(const 6u32, (_1.3: u32)); +// switchInt(move _5) -> [false: bb6, otherwise: bb5]; +// } +// bb5: { +// _6 = Le((_1.3: u32), const 9u32); +// switchInt(move _6) -> [false: bb6, otherwise: bb8]; +// } +// bb6: { +// _3 = Le(const 13u32, (_1.3: u32)); +// switchInt(move _3) -> [false: bb1, otherwise: bb7]; +// } +// bb7: { +// _4 = Le((_1.3: u32), const 16u32); +// switchInt(move _4) -> [false: bb1, otherwise: bb8]; +// } +// bb8: { +// falseEdges -> [real: bb9, imaginary: bb1]; +// } +// bb9: { +// StorageLive(_7); +// _7 = (_1.0: u32); +// StorageLive(_8); +// _8 = (_1.3: u32); +// StorageLive(_9); +// _9 = _7; +// StorageLive(_10); +// StorageLive(_11); +// _11 = _8; +// _10 = Mul(const 2u32, move _11); +// StorageDead(_11); +// _0 = Add(move _9, move _10); +// StorageDead(_10); +// StorageDead(_9); +// StorageDead(_8); +// StorageDead(_7); +// goto -> bb10; +// } +// bb10: { +// return; +// } +// END rustc.match_tuple.SimplifyCfg-initial.after.mir diff --git a/src/test/mir-opt/issue-62289.rs b/src/test/mir-opt/issue-62289.rs index a3b517e9bca87..8e619ffdf8b96 100644 --- a/src/test/mir-opt/issue-62289.rs +++ b/src/test/mir-opt/issue-62289.rs @@ -32,47 +32,47 @@ fn main() { // bb2: { // StorageDead(_4); // _5 = discriminant(_3); -// switchInt(move _5) -> [0isize: bb10, 1isize: bb5, otherwise: bb4]; +// switchInt(move _5) -> [0isize: bb4, 1isize: bb6, otherwise: bb5]; // } // bb3 (cleanup): { // drop(_2) -> bb1; // } // bb4: { -// unreachable; +// StorageLive(_10); +// _10 = ((_3 as Ok).0: u32); +// (*_2) = _10; +// StorageDead(_10); +// _1 = move _2; +// drop(_2) -> [return: bb12, unwind: bb11]; // } // bb5: { +// unreachable; +// } +// bb6: { // StorageLive(_6); // _6 = ((_3 as Err).0: std::option::NoneError); // StorageLive(_8); // StorageLive(_9); // _9 = _6; -// _8 = const >::from(move _9) -> [return: bb7, unwind: bb3]; +// _8 = const >::from(move _9) -> [return: bb8, unwind: bb3]; // } -// bb6: { +// bb7: { // return; // } -// bb7: { +// bb8: { // StorageDead(_9); -// _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb8, unwind: bb3]; +// _0 = const > as std::ops::Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // } -// bb8: { +// bb9: { // StorageDead(_8); // StorageDead(_6); -// drop(_2) -> bb9; +// drop(_2) -> bb10; // } -// bb9: { +// bb10: { // StorageDead(_2); // StorageDead(_1); // StorageDead(_3); -// goto -> bb6; -// } -// bb10: { -// StorageLive(_10); -// _10 = ((_3 as Ok).0: u32); -// (*_2) = _10; -// StorageDead(_10); -// _1 = move _2; -// drop(_2) -> [return: bb12, unwind: bb11]; +// goto -> bb7; // } // bb11 (cleanup): { // drop(_1) -> bb1; @@ -85,7 +85,7 @@ fn main() { // bb13: { // StorageDead(_1); // StorageDead(_3); -// goto -> bb6; +// goto -> bb7; // } // } // END rustc.test.ElaborateDrops.before.mir diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs index 4412a16e74d5e..7afc3bbd6fae8 100644 --- a/src/test/mir-opt/match-arm-scopes.rs +++ b/src/test/mir-opt/match-arm-scopes.rs @@ -28,10 +28,7 @@ const CASES: &[(bool, bool, bool, i32)] = &[ fn main() { for &(cond, items_1, items_2, result) in CASES { - assert_eq!( - complicated_match(cond, (items_1, items_2, String::new())), - result, - ); + assert_eq!(complicated_match(cond, (items_1, items_2, String::new())), result,); } } @@ -64,31 +61,38 @@ fn main() { // } // bb0: { // FakeRead(ForMatchedPlace, _2); -// switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb5]; +// switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb3]; // } // bb1 (cleanup): { // resume; // } -// bb2: { -// falseEdges -> [real: bb8, imaginary: bb3]; +// bb2: { // pre-binding for arm 1 first pattern +// falseEdges -> [real: bb9, imaginary: bb4]; // } // bb3: { -// falseEdges -> [real: bb17, imaginary: bb4]; +// switchInt((_2.1: bool)) -> [false: bb4, otherwise: bb5]; // } -// bb4: { -// falseEdges -> [real: bb25, imaginary: bb26]; +// bb4: { // pre-binding for arm 1 second pattern +// falseEdges -> [real: bb18, imaginary: bb6]; // } // bb5: { -// switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb6]; +// switchInt((_2.0: bool)) -> [false: bb7, otherwise: bb6]; // } -// bb6: { -// switchInt((_2.0: bool)) -> [false: bb26, otherwise: bb4]; +// bb6: { // pre-binding for arm 2 first pattern +// falseEdges -> [real: bb26, imaginary: bb7]; // } -// bb7: { // arm 1 +// bb7: { // bindings for arm 2 - second pattern +// StorageLive(_15); +// _15 = (_2.1: bool); +// StorageLive(_16); +// _16 = move (_2.2: std::string::String); +// goto -> bb25; +// } +// bb8: { // arm 1 // _0 = const 1i32; -// drop(_7) -> [return: bb23, unwind: bb13]; +// drop(_7) -> [return: bb24, unwind: bb14]; // } -// bb8: { // guard - first time +// bb9: { // guard - first time // StorageLive(_6); // _6 = &(_2.1: bool); // StorageLive(_8); @@ -99,34 +103,34 @@ fn main() { // StorageLive(_10); // _10 = _1; // FakeRead(ForMatchedPlace, _10); -// switchInt(_10) -> [false: bb10, otherwise: bb9]; +// switchInt(_10) -> [false: bb11, otherwise: bb10]; // } -// bb9: { -// falseEdges -> [real: bb11, imaginary: bb10]; +// bb10: { +// falseEdges -> [real: bb12, imaginary: bb11]; // } -// bb10: { // `else` block - first time +// bb11: { // `else` block - first time // _9 = (*_6); // StorageDead(_10); -// switchInt(move _9) -> [false: bb16, otherwise: bb15]; +// switchInt(move _9) -> [false: bb17, otherwise: bb16]; // } -// bb11: { // `return 3` - first time +// bb12: { // `return 3` - first time // _0 = const 3i32; // StorageDead(_10); // StorageDead(_9); // StorageDead(_8); // StorageDead(_6); -// goto -> bb14; +// goto -> bb15; // } -// bb12: { +// bb13: { // return; // } -// bb13 (cleanup): { +// bb14 (cleanup): { // drop(_2) -> bb1; // } -// bb14: { -// drop(_2) -> [return: bb12, unwind: bb1]; -// } // bb15: { +// drop(_2) -> [return: bb13, unwind: bb1]; +// } +// bb16: { // StorageDead(_9); // FakeRead(ForMatchGuard, _3); // FakeRead(ForMatchGuard, _4); @@ -136,15 +140,15 @@ fn main() { // _5 = (_2.1: bool); // StorageLive(_7); // _7 = move (_2.2: std::string::String); -// goto -> bb7; +// goto -> bb8; // } -// bb16: { // guard otherwise case - first time +// bb17: { // guard otherwise case - first time // StorageDead(_9); // StorageDead(_8); // StorageDead(_6); -// falseEdges -> [real: bb5, imaginary: bb3]; +// falseEdges -> [real: bb3, imaginary: bb4]; // } -// bb17: { // guard - second time +// bb18: { // guard - second time // StorageLive(_6); // _6 = &(_2.0: bool); // StorageLive(_8); @@ -155,25 +159,25 @@ fn main() { // StorageLive(_13); // _13 = _1; // FakeRead(ForMatchedPlace, _13); -// switchInt(_13) -> [false: bb19, otherwise: bb18]; +// switchInt(_13) -> [false: bb20, otherwise: bb19]; // } -// bb18: { -// falseEdges -> [real: bb20, imaginary: bb19]; +// bb19: { +// falseEdges -> [real: bb21, imaginary: bb20]; // } -// bb19: { // `else` block - second time +// bb20: { // `else` block - second time // _12 = (*_6); // StorageDead(_13); -// switchInt(move _12) -> [false: bb22, otherwise: bb21]; +// switchInt(move _12) -> [false: bb23, otherwise: bb22]; // } -// bb20: { +// bb21: { // _0 = const 3i32; // StorageDead(_13); // StorageDead(_12); // StorageDead(_8); // StorageDead(_6); -// goto -> bb14; +// goto -> bb15; // } -// bb21: { // bindings for arm 1 +// bb22: { // bindings for arm 1 // StorageDead(_12); // FakeRead(ForMatchGuard, _3); // FakeRead(ForMatchGuard, _4); @@ -183,46 +187,40 @@ fn main() { // _5 = (_2.0: bool); // StorageLive(_7); // _7 = move (_2.2: std::string::String); -// goto -> bb7; +// goto -> bb8; // } -// bb22: { // Guard otherwise case - second time +// bb23: { // Guard otherwise case - second time // StorageDead(_12); // StorageDead(_8); // StorageDead(_6); -// falseEdges -> [real: bb6, imaginary: bb4]; +// falseEdges -> [real: bb5, imaginary: bb6]; // } -// bb23: { // rest of arm 1 +// bb24: { // rest of arm 1 // StorageDead(_7); // StorageDead(_5); // StorageDead(_8); // StorageDead(_6); // goto -> bb28; // } -// bb24: { // arm 2 +// bb25: { // arm 2 // _0 = const 2i32; -// drop(_16) -> [return: bb27, unwind: bb13]; +// drop(_16) -> [return: bb27, unwind: bb14]; // } -// bb25: { // bindings for arm 2 - first pattern +// bb26: { // bindings for arm 2 - first pattern // StorageLive(_15); // _15 = (_2.1: bool); // StorageLive(_16); // _16 = move (_2.2: std::string::String); -// goto -> bb24; -// } -// bb26: { // bindings for arm 2 - second pattern -// StorageLive(_15); -// _15 = (_2.1: bool); -// StorageLive(_16); -// _16 = move (_2.2: std::string::String); -// goto -> bb24; +// goto -> bb25; // } + // bb27: { // rest of arm 2 // StorageDead(_16); // StorageDead(_15); // goto -> bb28; // } // bb28: { -// drop(_2) -> [return: bb12, unwind: bb1]; +// drop(_2) -> [return: bb13, unwind: bb1]; // } // END rustc.complicated_match.SimplifyCfg-initial.after.mir // START rustc.complicated_match.ElaborateDrops.after.mir diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 648856b5523d3..893d198431ced 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -4,7 +4,7 @@ fn guard() -> bool { false } -fn guard2(_:i32) -> bool { +fn guard2(_: i32) -> bool { true } @@ -45,20 +45,20 @@ fn main() { // _2 = std::option::Option::::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _3 = discriminant(_2); -// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb5]; +// switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb5]; // } // bb1 (cleanup): { // resume; // } -// bb2: { -// falseEdges -> [real: bb6, imaginary: bb3]; //pre_binding1 +// bb2: { // pre_binding3 and arm3 +// _1 = (const 3i32, const 3i32); +// goto -> bb11; // } // bb3: { -// falseEdges -> [real: bb10, imaginary: bb4]; //pre_binding2 +// falseEdges -> [real: bb6, imaginary: bb4]; //pre_binding1 // } -// bb4: { //pre_binding3 and arm3 -// _1 = (const 3i32, const 3i32); -// goto -> bb11; +// bb4: { +// falseEdges -> [real: bb10, imaginary: bb2]; //pre_binding2 // } // bb5: { // unreachable; @@ -90,7 +90,7 @@ fn main() { // bb9: { // to pre_binding2 // StorageDead(_7); // StorageDead(_6); -// goto -> bb3; +// goto -> bb4; // } // bb10: { // arm2 // StorageLive(_9); @@ -102,7 +102,7 @@ fn main() { // StorageDead(_9); // goto -> bb11; // } -// bb11: { // arm3 +// bb11: { // StorageDead(_2); // StorageDead(_1); // _0 = (); @@ -116,31 +116,41 @@ fn main() { // _2 = std::option::Option::::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _3 = discriminant(_2); -// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb4]; +// switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb5]; // } // bb1 (cleanup): { // resume; // } -// bb2: { -// falseEdges -> [real: bb5, imaginary: bb3]; +// bb2: { // pre_binding2 +// falseEdges -> [real: bb10, imaginary: bb4]; // } -// bb3: { -// falseEdges -> [real: bb9, imaginary: bb10]; +// bb3: { // pre_binding1 +// falseEdges -> [real: bb6, imaginary: bb2]; // } -// bb4: { // to arm3 (can skip 2 since this is `Some`) +// bb4: { // binding3 and arm3 +// StorageLive(_9); +// _9 = ((_2 as Some).0: i32); +// StorageLive(_10); +// _10 = _9; +// _1 = (const 2i32, move _10); +// StorageDead(_10); +// StorageDead(_9); +// goto -> bb11; +// } +// bb5: { // unreachable; // } -// bb5: { // binding1 and guard +// bb6: { // StorageLive(_6); // _6 = &((_2 as Some).0: i32); // _4 = &shallow _2; // StorageLive(_7); -// _7 = const guard() -> [return: bb6, unwind: bb1]; +// _7 = const guard() -> [return: bb7, unwind: bb1]; // } -// bb6: { // end of guard -// switchInt(move _7) -> [false: bb8, otherwise: bb7]; +// bb7: { // end of guard +// switchInt(move _7) -> [false: bb9, otherwise: bb8]; // } -// bb7: { +// bb8: { // StorageDead(_7); // FakeRead(ForMatchGuard, _4); // FakeRead(ForGuardBinding, _6); @@ -154,25 +164,15 @@ fn main() { // StorageDead(_6); // goto -> bb11; // } -// bb8: { // to pre_binding3 (can skip 2 since this is `Some`) +// bb9: { // to pre_binding3 (can skip 2 since this is `Some`) // StorageDead(_7); // StorageDead(_6); -// falseEdges -> [real: bb10, imaginary: bb3]; +// falseEdges -> [real: bb4, imaginary: bb2]; // } -// bb9: { // arm2 +// bb10: { // arm2 // _1 = (const 3i32, const 3i32); // goto -> bb11; // } -// bb10: { // binding3 and arm3 -// StorageLive(_9); -// _9 = ((_2 as Some).0: i32); -// StorageLive(_10); -// _10 = _9; -// _1 = (const 2i32, move _10); -// StorageDead(_10); -// StorageDead(_9); -// goto -> bb11; -// } // bb11: { // StorageDead(_2); // StorageDead(_1); @@ -187,31 +187,38 @@ fn main() { // _2 = std::option::Option::::Some(const 1i32,); // FakeRead(ForMatchedPlace, _2); // _4 = discriminant(_2); -// switchInt(move _4) -> [1isize: bb2, otherwise: bb3]; +// switchInt(move _4) -> [1isize: bb3, otherwise: bb2]; // } // bb1 (cleanup): { // resume; // } // bb2: { -// falseEdges -> [real: bb5, imaginary: bb3]; +// falseEdges -> [real: bb10, imaginary: bb5]; // } // bb3: { -// falseEdges -> [real: bb9, imaginary: bb4]; +// falseEdges -> [real: bb6, imaginary: bb2]; // } // bb4: { -// falseEdges -> [real: bb10, imaginary: bb14]; +// StorageLive(_14); +// _14 = _2; +// _1 = const 4i32; +// StorageDead(_14); +// goto -> bb15; // } // bb5: { +// falseEdges -> [real: bb11, imaginary: bb4]; +// } +// bb6: { //end of guard1 // StorageLive(_7); // _7 = &((_2 as Some).0: i32); // _5 = &shallow _2; // StorageLive(_8); -// _8 = const guard() -> [return: bb6, unwind: bb1]; -// } -// bb6: { //end of guard1 -// switchInt(move _8) -> [false: bb8, otherwise: bb7]; +// _8 = const guard() -> [return: bb7, unwind: bb1]; // } // bb7: { +// switchInt(move _8) -> [false: bb9, otherwise: bb8]; +// } +// bb8: { // StorageDead(_8); // FakeRead(ForMatchGuard, _5); // FakeRead(ForGuardBinding, _7); @@ -222,32 +229,32 @@ fn main() { // StorageDead(_7); // goto -> bb15; // } -// bb8: { +// bb9: { // StorageDead(_8); // StorageDead(_7); -// falseEdges -> [real: bb3, imaginary: bb3]; +// falseEdges -> [real: bb2, imaginary: bb2]; // } -// bb9: { // binding2 & arm2 +// bb10: { // binding2 & arm2 // StorageLive(_9); // _9 = _2; // _1 = const 2i32; // StorageDead(_9); // goto -> bb15; // } -// bb10: { // binding3: Some(y) if guard2(y) +// bb11: { // binding3: Some(y) if guard2(y) // StorageLive(_11); // _11 = &((_2 as Some).0: i32); // _5 = &shallow _2; // StorageLive(_12); // StorageLive(_13); // _13 = (*_11); -// _12 = const guard2(move _13) -> [return: bb11, unwind: bb1]; +// _12 = const guard2(move _13) -> [return: bb12, unwind: bb1]; // } -// bb11: { // end of guard2 +// bb12: { // end of guard2 // StorageDead(_13); -// switchInt(move _12) -> [false: bb13, otherwise: bb12]; +// switchInt(move _12) -> [false: bb14, otherwise: bb13]; // } -// bb12: { // binding4 & arm4 +// bb13: { // binding4 & arm4 // StorageDead(_12); // FakeRead(ForMatchGuard, _5); // FakeRead(ForGuardBinding, _11); @@ -258,17 +265,10 @@ fn main() { // StorageDead(_11); // goto -> bb15; // } -// bb13: { +// bb14: { // StorageDead(_12); // StorageDead(_11); -// falseEdges -> [real: bb14, imaginary: bb14]; -// } -// bb14: { -// StorageLive(_14); -// _14 = _2; -// _1 = const 4i32; -// StorageDead(_14); -// goto -> bb15; +// falseEdges -> [real: bb4, imaginary: bb4]; // } // bb15: { // StorageDead(_2); diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs index 1ca75b100410b..5ee3e1447d832 100644 --- a/src/test/mir-opt/match_test.rs +++ b/src/test/mir-opt/match_test.rs @@ -20,35 +20,35 @@ fn main() { // START rustc.main.SimplifyCfg-initial.after.mir // bb0: { // ... -// switchInt(move _6) -> [false: bb6, otherwise: bb5]; +// switchInt(move _6) -> [false: bb4, otherwise: bb1]; // } // bb1: { -// falseEdges -> [real: bb9, imaginary: bb2]; +// _7 = Lt(_1, const 10i32); +// switchInt(move _7) -> [false: bb4, otherwise: bb2]; // } // bb2: { -// falseEdges -> [real: bb12, imaginary: bb3]; +// falseEdges -> [real: bb9, imaginary: bb6]; // } // bb3: { -// falseEdges -> [real: bb13, imaginary: bb4]; -// } -// bb4: { // _3 = const 3i32; // goto -> bb14; // } +// bb4: { +// _4 = Le(const 10i32, _1); +// switchInt(move _4) -> [false: bb7, otherwise: bb5]; +// } // bb5: { -// _7 = Lt(_1, const 10i32); -// switchInt(move _7) -> [false: bb6, otherwise: bb1]; +// _5 = Le(_1, const 20i32); +// switchInt(move _5) -> [false: bb7, otherwise: bb6]; // } // bb6: { -// _4 = Le(const 10i32, _1); -// switchInt(move _4) -> [false: bb8, otherwise: bb7]; +// falseEdges -> [real: bb12, imaginary: bb8]; // } // bb7: { -// _5 = Le(_1, const 20i32); -// switchInt(move _5) -> [false: bb8, otherwise: bb2]; +// switchInt(_1) -> [-1i32: bb8, otherwise: bb3]; // } // bb8: { -// switchInt(_1) -> [-1i32: bb3, otherwise: bb4]; +// falseEdges -> [real: bb13, imaginary: bb3]; // } // bb9: { // _8 = &shallow _1; @@ -64,7 +64,7 @@ fn main() { // } // bb11: { // StorageDead(_9); -// falseEdges -> [real: bb4, imaginary: bb2]; +// falseEdges -> [real: bb3, imaginary: bb6]; // } // bb12: { // _3 = const 1i32; diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs index 965897ad541e7..294fe247c38be 100644 --- a/src/test/mir-opt/remove_fake_borrows.rs +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -19,17 +19,17 @@ fn main() { // bb0: { // FakeRead(ForMatchedPlace, _1); // _3 = discriminant(_1); -// switchInt(move _3) -> [1isize: bb3, otherwise: bb2]; +// switchInt(move _3) -> [1isize: bb2, otherwise: bb1]; // } // bb1: { -// goto -> bb4; -// } -// bb2: { // _0 = const 1i32; // goto -> bb7; // } +// bb2: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb1]; +// } // bb3: { -// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb1, otherwise: bb2]; +// goto -> bb4; // } // bb4: { // _4 = &shallow _1; @@ -51,7 +51,7 @@ fn main() { // } // bb6: { // StorageDead(_8); -// goto -> bb2; +// goto -> bb1; // } // bb7: { // return; @@ -65,17 +65,17 @@ fn main() { // bb0: { // nop; // _3 = discriminant(_1); -// switchInt(move _3) -> [1isize: bb3, otherwise: bb2]; +// switchInt(move _3) -> [1isize: bb2, otherwise: bb1]; // } // bb1: { -// goto -> bb4; -// } -// bb2: { // _0 = const 1i32; // goto -> bb7; // } +// bb2: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb1]; +// } // bb3: { -// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb1, otherwise: bb2]; +// goto -> bb4; // } // bb4: { // nop; @@ -97,7 +97,7 @@ fn main() { // } // bb6: { // StorageDead(_8); -// goto -> bb2; +// goto -> bb1; // } // bb7: { // return; diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index 656b405ef340e..d66101d161403 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -47,25 +47,25 @@ fn main() { // } // bb0: { // _5 = discriminant(_1); -// switchInt(move _5) -> [0isize: bb4, 1isize: bb2, otherwise: bb1]; +// switchInt(move _5) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // } // bb1: { -// unreachable; +// _10 = ((_1 as Ok).0: u32); +// ((_0 as Ok).0: u32) = move _10; +// discriminant(_0) = 0; +// goto -> bb4; // } // bb2: { +// unreachable; +// } +// bb3: { // _6 = ((_1 as Err).0: i32); // ((_0 as Err).0: i32) = move _6; // discriminant(_0) = 1; -// goto -> bb3; -// } -// bb3: { -// return; +// goto -> bb4; // } // bb4: { -// _10 = ((_1 as Ok).0: u32); -// ((_0 as Ok).0: u32) = move _10; -// discriminant(_0) = 0; -// goto -> bb3; +// return; // } // } // END rustc.try_identity.SimplifyArmIdentity.before.mir @@ -109,25 +109,25 @@ fn main() { // } // bb0: { // _5 = discriminant(_1); -// switchInt(move _5) -> [0isize: bb4, 1isize: bb2, otherwise: bb1]; +// switchInt(move _5) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // } // bb1: { -// unreachable; -// } -// bb2: { // _0 = move _1; // nop; // nop; -// goto -> bb3; +// goto -> bb4; // } -// bb3: { -// return; +// bb2: { +// unreachable; // } -// bb4: { +// bb3: { // _0 = move _1; // nop; // nop; -// goto -> bb3; +// goto -> bb4; +// } +// bb4: { +// return; // } // } // END rustc.try_identity.SimplifyArmIdentity.after.mir @@ -171,16 +171,16 @@ fn main() { // } // bb0: { // _5 = discriminant(_1); -// goto -> bb2; +// goto -> bb1; // } // bb1: { -// return; -// } -// bb2: { // _0 = move _1; // nop; // nop; -// goto -> bb1; +// goto -> bb2; +// } +// bb2: { +// return; // } // } // END rustc.try_identity.SimplifyBranchSame.after.mir diff --git a/src/test/ui/borrowck/or-patterns.rs b/src/test/ui/borrowck/or-patterns.rs new file mode 100644 index 0000000000000..5b31e2d76a05b --- /dev/null +++ b/src/test/ui/borrowck/or-patterns.rs @@ -0,0 +1,64 @@ +// Test that borrow check considers all choices in an or pattern, even the +// unreachable ones. + +#![feature(or_patterns)] + +fn or_pattern_moves_all(x: ((String, String),)) { + match x { + ((y, _) | (_, y),) => (), + } + &x.0 .0; + //~^ ERROR borrow of moved value + &x.0 .1; + //~^ ERROR borrow of moved value +} + +fn or_pattern_borrows_all(mut x: ((String, String),)) { + let r = match x { + ((ref y, _) | (_, ref y),) => y, + }; + &mut x.0 .0; + //~^ ERROR cannot borrow + &mut x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn or_pattern_borrows_all_mut(mut x: ((String, String),)) { + let r = match x { + ((ref mut y, _) | (_, ref mut y),) => y, + }; + &x.0 .0; + //~^ ERROR cannot borrow + &x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn let_or_pattern_moves_all(x: ((String, String),)) { + let ((y, _) | (_, y),) = x; + &x.0 .0; + //~^ ERROR borrow of moved value + &x.0 .1; + //~^ ERROR borrow of moved value +} + +fn let_or_pattern_borrows_all(mut x: ((String, String),)) { + let ((ref r, _) | (_, ref r),) = x; + &mut x.0 .0; + //~^ ERROR cannot borrow + &mut x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn let_or_pattern_borrows_all_mut(mut x: ((String, String),)) { + let ((ref mut r, _) | (_, ref mut r),) = x; + &x.0 .0; + //~^ ERROR cannot borrow + &x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn main() {} diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr new file mode 100644 index 0000000000000..d3f3544426aad --- /dev/null +++ b/src/test/ui/borrowck/or-patterns.stderr @@ -0,0 +1,141 @@ +error[E0382]: borrow of moved value: `x.0.0` + --> $DIR/or-patterns.rs:10:5 + | +LL | ((y, _) | (_, y),) => (), + | - value moved here +LL | } +LL | &x.0 .0; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `x.0.1` + --> $DIR/or-patterns.rs:12:5 + | +LL | ((y, _) | (_, y),) => (), + | - value moved here +... +LL | &x.0 .1; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:20:5 + | +LL | ((ref y, _) | (_, ref y),) => y, + | ----- immutable borrow occurs here +LL | }; +LL | &mut x.0 .0; + | ^^^^^^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:22:5 + | +LL | ((ref y, _) | (_, ref y),) => y, + | ----- immutable borrow occurs here +... +LL | &mut x.0 .1; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:31:5 + | +LL | ((ref mut y, _) | (_, ref mut y),) => y, + | --------- mutable borrow occurs here +LL | }; +LL | &x.0 .0; + | ^^^^^^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:33:5 + | +LL | ((ref mut y, _) | (_, ref mut y),) => y, + | --------- mutable borrow occurs here +... +LL | &x.0 .1; + | ^^^^^^^ immutable borrow occurs here +LL | +LL | drop(r); + | - mutable borrow later used here + +error[E0382]: borrow of moved value: `x.0.0` + --> $DIR/or-patterns.rs:40:5 + | +LL | let ((y, _) | (_, y),) = x; + | - value moved here +LL | &x.0 .0; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `x.0.1` + --> $DIR/or-patterns.rs:42:5 + | +LL | let ((y, _) | (_, y),) = x; + | - value moved here +... +LL | &x.0 .1; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:48:5 + | +LL | let ((ref r, _) | (_, ref r),) = x; + | ----- immutable borrow occurs here +LL | &mut x.0 .0; + | ^^^^^^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:50:5 + | +LL | let ((ref r, _) | (_, ref r),) = x; + | ----- immutable borrow occurs here +... +LL | &mut x.0 .1; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:57:5 + | +LL | let ((ref mut r, _) | (_, ref mut r),) = x; + | --------- mutable borrow occurs here +LL | &x.0 .0; + | ^^^^^^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:59:5 + | +LL | let ((ref mut r, _) | (_, ref mut r),) = x; + | --------- mutable borrow occurs here +... +LL | &x.0 .1; + | ^^^^^^^ immutable borrow occurs here +LL | +LL | drop(r); + | - mutable borrow later used here + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0382, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/consts/const_let_refutable.rs b/src/test/ui/consts/const_let_refutable.rs index d48d5945e7da9..e49d47673912a 100644 --- a/src/test/ui/consts/const_let_refutable.rs +++ b/src/test/ui/consts/const_let_refutable.rs @@ -1,7 +1,7 @@ fn main() {} -const fn slice([a, b]: &[i32]) -> i32 { //~ ERROR refutable pattern in function argument - a + b //~ ERROR can only call other `const fn` within a `const fn` - //~^ ERROR use of possibly-uninitialized variable: `a` - //~| ERROR use of possibly-uninitialized variable: `b` +const fn slice(&[a, b]: &[i32]) -> i32 { + //~^ ERROR refutable pattern in function argument + //~| ERROR loops and conditional expressions are not stable in const fn + a + b } diff --git a/src/test/ui/consts/const_let_refutable.stderr b/src/test/ui/consts/const_let_refutable.stderr index 9acb4ad9cbbe5..719e14005ffa4 100644 --- a/src/test/ui/consts/const_let_refutable.stderr +++ b/src/test/ui/consts/const_let_refutable.stderr @@ -1,31 +1,19 @@ error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _, ..]` not covered --> $DIR/const_let_refutable.rs:3:16 | -LL | const fn slice([a, b]: &[i32]) -> i32 { - | ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered +LL | const fn slice(&[a, b]: &[i32]) -> i32 { + | ^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered -error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn` - --> $DIR/const_let_refutable.rs:4:5 +error[E0723]: loops and conditional expressions are not stable in const fn + --> $DIR/const_let_refutable.rs:3:17 | -LL | a + b - | ^^^^^ +LL | const fn slice(&[a, b]: &[i32]) -> i32 { + | ^^^^^^ | = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0381]: use of possibly-uninitialized variable: `a` - --> $DIR/const_let_refutable.rs:4:5 - | -LL | a + b - | ^ use of possibly-uninitialized `a` - -error[E0381]: use of possibly-uninitialized variable: `b` - --> $DIR/const_let_refutable.rs:4:9 - | -LL | a + b - | ^ use of possibly-uninitialized `b` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0005, E0381, E0723. +Some errors have detailed explanations: E0005, E0723. For more information about an error, try `rustc --explain E0005`. diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs index f0ecea42f39c8..01b99134a445f 100644 --- a/src/test/ui/empty/empty-never-array.rs +++ b/src/test/ui/empty/empty-never-array.rs @@ -10,7 +10,6 @@ fn transmute(t: T) -> U { let Helper::U(u) = Helper::T(t, []); //~^ ERROR refutable pattern in local binding: `T(_, _)` not covered u - //~^ ERROR use of possibly-uninitialized variable: `u` } fn main() { diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index d865b59f0b945..a4ffceea4c97f 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -19,13 +19,6 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | if let Helper::U(u) = Helper::T(t, []) { /* */ } | -error[E0381]: use of possibly-uninitialized variable: `u` - --> $DIR/empty-never-array.rs:12:5 - | -LL | u - | ^ use of possibly-uninitialized `u` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0005, E0381. -For more information about an error, try `rustc --explain E0005`. +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/issues/issue-12567.stderr b/src/test/ui/issues/issue-12567.stderr index 9d9a88f4f9b06..52d4eda79d0fc 100644 --- a/src/test/ui/issues/issue-12567.stderr +++ b/src/test/ui/issues/issue-12567.stderr @@ -8,7 +8,7 @@ LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) | -- data moved here LL | => println!("one empty"), LL | (&[hd1, ..], &[hd2, ..]) - | --- ...and here + | --- ...and here | = note: move occurs because these variables have types that don't implement the `Copy` trait @@ -22,7 +22,7 @@ LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) | -- data moved here LL | => println!("one empty"), LL | (&[hd1, ..], &[hd2, ..]) - | --- ...and here + | --- ...and here | = note: move occurs because these variables have types that don't implement the `Copy` trait diff --git a/src/test/ui/issues/issue-15381.rs b/src/test/ui/issues/issue-15381.rs index 5307153cb4403..392fb1b24ddc4 100644 --- a/src/test/ui/issues/issue-15381.rs +++ b/src/test/ui/issues/issue-15381.rs @@ -4,6 +4,5 @@ fn main() { for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { //~^ ERROR refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not println!("y={}", y); - //~^ ERROR borrow of possibly-uninitialized variable: `y` } } diff --git a/src/test/ui/issues/issue-15381.stderr b/src/test/ui/issues/issue-15381.stderr index 47a0d514ad873..35f46ab57279c 100644 --- a/src/test/ui/issues/issue-15381.stderr +++ b/src/test/ui/issues/issue-15381.stderr @@ -4,13 +4,6 @@ error[E0005]: refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { | ^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered -error[E0381]: borrow of possibly-uninitialized variable: `y` - --> $DIR/issue-15381.rs:6:26 - | -LL | println!("y={}", y); - | ^ use of possibly-uninitialized `y` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0005, E0381. -For more information about an error, try `rustc --explain E0005`. +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.rs b/src/test/ui/lint/issue-54538-unused-parens-lint.rs index 7dcbdd0863cbd..f3d2d1bb58d8f 100644 --- a/src/test/ui/lint/issue-54538-unused-parens-lint.rs +++ b/src/test/ui/lint/issue-54538-unused-parens-lint.rs @@ -1,7 +1,6 @@ #![feature(box_patterns, stmt_expr_attributes)] #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete #![allow(ellipsis_inclusive_range_patterns)] #![allow(unreachable_patterns)] diff --git a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr index 675dd4f07def6..9cfe491adb108 100644 --- a/src/test/ui/lint/issue-54538-unused-parens-lint.stderr +++ b/src/test/ui/lint/issue-54538-unused-parens-lint.stderr @@ -1,157 +1,149 @@ -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/issue-54538-unused-parens-lint.rs:3:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:12:9 + --> $DIR/issue-54538-unused-parens-lint.rs:11:9 | LL | let (a) = 0; | ^^^ help: remove these parentheses | note: lint level defined here - --> $DIR/issue-54538-unused-parens-lint.rs:9:9 + --> $DIR/issue-54538-unused-parens-lint.rs:8:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:13:9 + --> $DIR/issue-54538-unused-parens-lint.rs:12:9 | LL | for (a) in 0..1 {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:14:12 + --> $DIR/issue-54538-unused-parens-lint.rs:13:12 | LL | if let (a) = 0 {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:15:15 + --> $DIR/issue-54538-unused-parens-lint.rs:14:15 | LL | while let (a) = 0 {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:16:12 + --> $DIR/issue-54538-unused-parens-lint.rs:15:12 | LL | fn foo((a): u8) {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:17:14 + --> $DIR/issue-54538-unused-parens-lint.rs:16:14 | LL | let _ = |(a): u8| 0; | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:45:12 + --> $DIR/issue-54538-unused-parens-lint.rs:44:12 | LL | if let (0 | 1) = 0 {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:46:13 + --> $DIR/issue-54538-unused-parens-lint.rs:45:13 | LL | if let ((0 | 1),) = (0,) {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:47:13 + --> $DIR/issue-54538-unused-parens-lint.rs:46:13 | LL | if let [(0 | 1)] = [0] {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:48:16 + --> $DIR/issue-54538-unused-parens-lint.rs:47:16 | LL | if let 0 | (1 | 2) = 0 {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:50:15 + --> $DIR/issue-54538-unused-parens-lint.rs:49:15 | LL | if let TS((0 | 1)) = TS(0) {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:52:20 + --> $DIR/issue-54538-unused-parens-lint.rs:51:20 | LL | if let NS { f: (0 | 1) } = (NS { f: 0 }) {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:62:9 + --> $DIR/issue-54538-unused-parens-lint.rs:61:9 | LL | (_) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:63:9 + --> $DIR/issue-54538-unused-parens-lint.rs:62:9 | LL | (y) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:64:9 + --> $DIR/issue-54538-unused-parens-lint.rs:63:9 | LL | (ref r) => {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:65:9 + --> $DIR/issue-54538-unused-parens-lint.rs:64:9 | LL | (e @ 1...2) => {} | ^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:71:9 + --> $DIR/issue-54538-unused-parens-lint.rs:70:9 | LL | (e @ &(1...2)) => {} | ^^^^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:72:10 + --> $DIR/issue-54538-unused-parens-lint.rs:71:10 | LL | &(_) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:83:9 + --> $DIR/issue-54538-unused-parens-lint.rs:82:9 | LL | (_) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:84:9 + --> $DIR/issue-54538-unused-parens-lint.rs:83:9 | LL | (y) => {} | ^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:85:9 + --> $DIR/issue-54538-unused-parens-lint.rs:84:9 | LL | (ref r) => {} | ^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:86:9 + --> $DIR/issue-54538-unused-parens-lint.rs:85:9 | LL | (e @ 1..=2) => {} | ^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:92:9 + --> $DIR/issue-54538-unused-parens-lint.rs:91:9 | LL | (e @ &(1..=2)) => {} | ^^^^^^^^^^^^^^ help: remove these parentheses error: unnecessary parentheses around pattern - --> $DIR/issue-54538-unused-parens-lint.rs:93:10 + --> $DIR/issue-54538-unused-parens-lint.rs:92:10 | LL | &(_) => {} | ^^^ help: remove these parentheses diff --git a/src/test/ui/or-patterns/already-bound-name.rs b/src/test/ui/or-patterns/already-bound-name.rs index 3ebf59c643735..726e17b7ec226 100644 --- a/src/test/ui/or-patterns/already-bound-name.rs +++ b/src/test/ui/or-patterns/already-bound-name.rs @@ -2,7 +2,6 @@ // correctly accounts for or-patterns. #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete enum E { A(T, T), B(T) } diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr index 360699a873938..e4dfe5b656679 100644 --- a/src/test/ui/or-patterns/already-bound-name.stderr +++ b/src/test/ui/or-patterns/already-bound-name.stderr @@ -1,97 +1,89 @@ error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:12:13 + --> $DIR/already-bound-name.rs:11:13 | LL | let (a, a) = (0, 1); // Standard duplication without an or-pattern. | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:15:15 + --> $DIR/already-bound-name.rs:14:15 | LL | let (a, A(a, _) | B(a)) = (0, A(1, 2)); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:15:25 + --> $DIR/already-bound-name.rs:14:25 | LL | let (a, A(a, _) | B(a)) = (0, A(1, 2)); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:19:26 + --> $DIR/already-bound-name.rs:18:26 | LL | let (A(a, _) | B(a), a) = (A(0, 1), 2); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:22:14 + --> $DIR/already-bound-name.rs:21:14 | LL | let A(a, a) | B(a) = A(0, 1); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:25:21 + --> $DIR/already-bound-name.rs:24:21 | LL | let B(a) | A(a, a) = A(0, 1); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:29:21 + --> $DIR/already-bound-name.rs:28:21 | LL | B(a) | A(a, a) => {} // Let's ensure `match` has no funny business. | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:33:36 + --> $DIR/already-bound-name.rs:32:36 | LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:33:46 + --> $DIR/already-bound-name.rs:32:46 | LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:38:36 + --> $DIR/already-bound-name.rs:37:36 | LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:38:46 + --> $DIR/already-bound-name.rs:37:46 | LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); | ^ used in a pattern more than once error[E0408]: variable `a` is not bound in all patterns - --> $DIR/already-bound-name.rs:38:9 + --> $DIR/already-bound-name.rs:37:9 | LL | let B(_) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); | ^^^^ pattern doesn't bind `a` - variable not in all patterns error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:43:49 + --> $DIR/already-bound-name.rs:42:49 | LL | let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/already-bound-name.rs:43:59 + --> $DIR/already-bound-name.rs:42:59 | LL | let B(A(a, _) | B(a)) | A(A(a, _) | B(a), A(a, _) | B(a)) = B(B(1)); | ^ used in a pattern more than once -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/already-bound-name.rs:4:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/already-bound-name.rs:33:31 + --> $DIR/already-bound-name.rs:32:31 | LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); | ^ expected integer, found enum `E` diff --git a/src/test/ui/or-patterns/basic-switch.rs b/src/test/ui/or-patterns/basic-switch.rs new file mode 100644 index 0000000000000..cbb665e7a7645 --- /dev/null +++ b/src/test/ui/or-patterns/basic-switch.rs @@ -0,0 +1,33 @@ +// Test basic or-patterns when the target pattern type will be lowered to a +// `SwitchInt` (an `enum`). + +// run-pass + +#![feature(or_patterns)] + +#[derive(Debug)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(x: Option) -> bool { + match x { + // most simple case + Some(Test::Bar | Test::Qux) => true, + // wild case + Some(_) => false, + // empty case + None => false, + } +} + +fn main() { + assert!(!test(Some(Test::Foo))); + assert!(test(Some(Test::Bar))); + assert!(!test(Some(Test::Baz))); + assert!(test(Some(Test::Qux))); + assert!(!test(None)) +} diff --git a/src/test/ui/or-patterns/basic-switchint.rs b/src/test/ui/or-patterns/basic-switchint.rs new file mode 100644 index 0000000000000..08c8252f3aecc --- /dev/null +++ b/src/test/ui/or-patterns/basic-switchint.rs @@ -0,0 +1,57 @@ +// Test basic or-patterns when the target pattern type will be lowered to +// a `Switch`. This will happen when the target type is an integer. + +// run-pass + +#![feature(or_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug)] +enum Foo { + One(usize), + Two(usize, usize), +} + +fn test_foo(x: Foo) -> MatchArm { + match x { + // normal pattern. + Foo::One(0) | Foo::One(1) | Foo::One(2) => MatchArm::Arm(0), + // most simple or-pattern. + Foo::One(42 | 255) => MatchArm::Arm(1), + // multiple or-patterns for one structure. + Foo::Two(42 | 255, 1024 | 2048) => MatchArm::Arm(2), + // mix of pattern types in one or-pattern (range). + // + // FIXME(dlrobertson | Nadrieril): Fix or-pattern completeness and + // unreachabilitychecks for ranges. + Foo::One(100 | 110..=120 | 210..=220) => MatchArm::Arm(3), + // multiple or-patterns with wild. + Foo::Two(0..=10 | 100..=110, 0 | _) => MatchArm::Arm(4), + // wild + _ => MatchArm::Wild, + } +} + +fn main() { + // `Foo` tests. + assert_eq!(test_foo(Foo::One(0)), MatchArm::Arm(0)); + assert_eq!(test_foo(Foo::One(42)), MatchArm::Arm(1)); + assert_eq!(test_foo(Foo::One(43)), MatchArm::Wild); + assert_eq!(test_foo(Foo::One(255)), MatchArm::Arm(1)); + assert_eq!(test_foo(Foo::One(256)), MatchArm::Wild); + assert_eq!(test_foo(Foo::Two(42, 1023)), MatchArm::Wild); + assert_eq!(test_foo(Foo::Two(255, 2048)), MatchArm::Arm(2)); + assert_eq!(test_foo(Foo::One(100)), MatchArm::Arm(3)); + assert_eq!(test_foo(Foo::One(115)), MatchArm::Arm(3)); + assert_eq!(test_foo(Foo::One(105)), MatchArm::Wild); + assert_eq!(test_foo(Foo::One(215)), MatchArm::Arm(3)); + assert_eq!(test_foo(Foo::One(121)), MatchArm::Wild); + assert_eq!(test_foo(Foo::Two(0, 42)), MatchArm::Arm(4)); + assert_eq!(test_foo(Foo::Two(100, 0)), MatchArm::Arm(4)); + assert_eq!(test_foo(Foo::Two(42, 0)), MatchArm::Wild); +} diff --git a/src/test/ui/or-patterns/bindings-runpass-1.rs b/src/test/ui/or-patterns/bindings-runpass-1.rs new file mode 100644 index 0000000000000..0087167af7ecc --- /dev/null +++ b/src/test/ui/or-patterns/bindings-runpass-1.rs @@ -0,0 +1,25 @@ +// run-pass + +#![feature(or_patterns)] + +fn two_bindings(x: &((bool, bool), u8)) -> u8 { + match x { + &((true, y) | (y, true), z @ (0 | 4)) => (y as u8) + z, + _ => 20, + } +} + +fn main() { + assert_eq!(two_bindings(&((false, false), 0)), 20); + assert_eq!(two_bindings(&((false, true), 0)), 0); + assert_eq!(two_bindings(&((true, false), 0)), 0); + assert_eq!(two_bindings(&((true, true), 0)), 1); + assert_eq!(two_bindings(&((false, false), 4)), 20); + assert_eq!(two_bindings(&((false, true), 4)), 4); + assert_eq!(two_bindings(&((true, false), 4)), 4); + assert_eq!(two_bindings(&((true, true), 4)), 5); + assert_eq!(two_bindings(&((false, false), 3)), 20); + assert_eq!(two_bindings(&((false, true), 3)), 20); + assert_eq!(two_bindings(&((true, false), 3)), 20); + assert_eq!(two_bindings(&((true, true), 3)), 20); +} diff --git a/src/test/ui/or-patterns/bindings-runpass-2.rs b/src/test/ui/or-patterns/bindings-runpass-2.rs new file mode 100644 index 0000000000000..0e1eb7b2e030b --- /dev/null +++ b/src/test/ui/or-patterns/bindings-runpass-2.rs @@ -0,0 +1,32 @@ +// run-pass + +#![feature(or_patterns)] + +fn or_at(x: Result) -> u32 { + match x { + Ok(x @ 4) | Err(x @ (6 | 8)) => x, + Ok(x @ 1 | x @ 2) => x, + Err(x @ (0..=10 | 30..=40)) if x % 2 == 0 => x + 100, + Err(x @ 0..=40) => x + 200, + _ => 500, + } +} + +fn main() { + assert_eq!(or_at(Ok(1)), 1); + assert_eq!(or_at(Ok(2)), 2); + assert_eq!(or_at(Ok(3)), 500); + assert_eq!(or_at(Ok(4)), 4); + assert_eq!(or_at(Ok(5)), 500); + assert_eq!(or_at(Ok(6)), 500); + assert_eq!(or_at(Err(1)), 201); + assert_eq!(or_at(Err(2)), 102); + assert_eq!(or_at(Err(3)), 203); + assert_eq!(or_at(Err(4)), 104); + assert_eq!(or_at(Err(5)), 205); + assert_eq!(or_at(Err(6)), 6); + assert_eq!(or_at(Err(7)), 207); + assert_eq!(or_at(Err(8)), 8); + assert_eq!(or_at(Err(20)), 220); + assert_eq!(or_at(Err(50)), 500); +} diff --git a/src/test/ui/or-patterns/consistent-bindings.rs b/src/test/ui/or-patterns/consistent-bindings.rs index 0eb539dca4cba..3ee57978bb009 100644 --- a/src/test/ui/or-patterns/consistent-bindings.rs +++ b/src/test/ui/or-patterns/consistent-bindings.rs @@ -2,8 +2,9 @@ // edition:2018 +// check-pass + #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete fn main() { // One level: @@ -12,35 +13,29 @@ fn main() { let Ok(ref mut a) | Err(ref mut a) = Ok(0); // Two levels: - enum Tri { V1(S), V2(T), V3(U) } + enum Tri { + V1(S), + V2(T), + V3(U), + } use Tri::*; - let Ok((V1(a) | V2(a) | V3(a), b)) | Err(Ok((a, b)) | Err((a, b))) - : Result<_, Result<_, _>> - = Ok((V1(1), 1)); + let Ok((V1(a) | V2(a) | V3(a), b)) | Err(Ok((a, b)) | Err((a, b))): Result<_, Result<_, _>> = + Ok((V1(1), 1)); - let Ok((V1(a) | V2(a) | V3(a), ref b)) | Err(Ok((a, ref b)) | Err((a, ref b))) - : Result<_, Result<_, _>> - = Ok((V1(1), 1)); + let Ok((V1(a) | V2(a) | V3(a), ref b)) | Err(Ok((a, ref b)) | Err((a, ref b))): Result< + _, + Result<_, _>, + > = Ok((V1(1), 1)); // Three levels: let ( - a, - Err((ref mut b, ref c, d)) | - Ok(( - Ok( - V1((ref c, d)) | - V2((d, ref c)) | - V3((ref c, Ok((_, d)) | Err((d, _)))) - ) | - Err((ref c, d)), - ref mut b - )) - ) = - (1, Ok((Ok(V3((1, Ok((1, 1))))), 1))); - - // FIXME(or_patterns; Centril | dlrobertson): remove this line below and - // change this test to check-pass once MIR can handle or-patterns with bindings. - let () = 0; - //~^ ERROR mismatched types + a, + Err((ref mut b, ref c, d)) + | Ok(( + Ok(V1((ref c, d)) | V2((d, ref c)) | V3((ref c, Ok((_, d)) | Err((d, _))))) + | Err((ref c, d)), + ref mut b, + )), + ): (_, Result<_, _>) = (1, Ok((Ok(V3((1, Ok::<_, (i32, i32)>((1, 1))))), 1))); } diff --git a/src/test/ui/or-patterns/consistent-bindings.stderr b/src/test/ui/or-patterns/consistent-bindings.stderr deleted file mode 100644 index 433a02dfb3139..0000000000000 --- a/src/test/ui/or-patterns/consistent-bindings.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/consistent-bindings.rs:5:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - -error[E0308]: mismatched types - --> $DIR/consistent-bindings.rs:44:9 - | -LL | let () = 0; - | ^^ expected integer, found `()` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs index d7c191bb5a28d..e0cf08b5598b9 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs @@ -1,23 +1,16 @@ #![feature(or_patterns)] #![feature(slice_patterns)] -#![allow(incomplete_features)] #![deny(unreachable_patterns)] -// We wrap patterns in a tuple because top-level or-patterns are special-cased for now. +// We wrap patterns in a tuple because top-level or-patterns were special-cased. fn main() { - // Get the fatal error out of the way - match (0u8,) { - (0 | _,) => {} - //~^ ERROR or-patterns are not fully implemented yet - } - match (0u8, 0u8) { //~^ ERROR non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` (0 | 1, 2 | 3) => {} } match ((0u8,),) { //~^ ERROR non-exhaustive patterns: `((4u8..=std::u8::MAX))` - ((0 | 1,) | (2 | 3,),) => {}, + ((0 | 1,) | (2 | 3,),) => {} } match (Some(0u8),) { //~^ ERROR non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index e6aa157d278c8..5ce7698a218ac 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` not covered - --> $DIR/exhaustiveness-non-exhaustive.rs:14:11 + --> $DIR/exhaustiveness-non-exhaustive.rs:7:11 | LL | match (0u8, 0u8) { | ^^^^^^^^^^ pattern `(2u8..=std::u8::MAX, _)` not covered @@ -7,7 +7,7 @@ LL | match (0u8, 0u8) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `((4u8..=std::u8::MAX))` not covered - --> $DIR/exhaustiveness-non-exhaustive.rs:18:11 + --> $DIR/exhaustiveness-non-exhaustive.rs:11:11 | LL | match ((0u8,),) { | ^^^^^^^^^ pattern `((4u8..=std::u8::MAX))` not covered @@ -15,19 +15,13 @@ LL | match ((0u8,),) { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms error[E0004]: non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` not covered - --> $DIR/exhaustiveness-non-exhaustive.rs:22:11 + --> $DIR/exhaustiveness-non-exhaustive.rs:15:11 | LL | match (Some(0u8),) { | ^^^^^^^^^^^^ pattern `(Some(2u8..=std::u8::MAX))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms -error: or-patterns are not fully implemented yet - --> $DIR/exhaustiveness-non-exhaustive.rs:10:10 - | -LL | (0 | _,) => {} - | ^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.rs b/src/test/ui/or-patterns/exhaustiveness-pass.rs index ce0fe6fc2a375..c11cbd28d2295 100644 --- a/src/test/ui/or-patterns/exhaustiveness-pass.rs +++ b/src/test/ui/or-patterns/exhaustiveness-pass.rs @@ -1,16 +1,11 @@ #![feature(or_patterns)] #![feature(slice_patterns)] -#![allow(incomplete_features)] #![deny(unreachable_patterns)] -// We wrap patterns in a tuple because top-level or-patterns are special-cased for now. -fn main() { - // Get the fatal error out of the way - match (0,) { - (0 | _,) => {} - //~^ ERROR or-patterns are not fully implemented yet - } +// check-pass +// We wrap patterns in a tuple because top-level or-patterns were special-cased. +fn main() { match (0,) { (1 | 2,) => {} _ => {} @@ -27,11 +22,11 @@ fn main() { (Some(2..=255),) => {} } match ((0,),) { - ((0 | 1,) | (2 | 3,),) => {}, - ((_,),) => {}, + ((0 | 1,) | (2 | 3,),) => {} + ((_,),) => {} } match (&[0u8][..],) { - ([] | [0 | 1..=255] | [_, ..],) => {}, + ([] | [0 | 1..=255] | [_, ..],) => {} } match ((0, 0),) { diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.stderr b/src/test/ui/or-patterns/exhaustiveness-pass.stderr deleted file mode 100644 index 1f4278c4b8098..0000000000000 --- a/src/test/ui/or-patterns/exhaustiveness-pass.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: or-patterns are not fully implemented yet - --> $DIR/exhaustiveness-pass.rs:10:10 - | -LL | (0 | _,) => {} - | ^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 860c7a1bde5fb..22bee448d7b73 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -1,16 +1,9 @@ #![feature(or_patterns)] #![feature(slice_patterns)] -#![allow(incomplete_features)] #![deny(unreachable_patterns)] -// We wrap patterns in a tuple because top-level or-patterns are special-cased for now. +// We wrap patterns in a tuple because top-level or-patterns were special-cased. fn main() { - // Get the fatal error out of the way - match (0u8,) { - (0 | _,) => {} - //~^ ERROR or-patterns are not fully implemented yet - } - match (0u8,) { (1 | 2,) => {} (1,) => {} //~ ERROR unreachable pattern @@ -29,9 +22,9 @@ fn main() { } match (0u8, 0u8) { (1 | 2, 3 | 4) => {} - (1, 3) => {} //~ ERROR unreachable pattern - (1, 4) => {} //~ ERROR unreachable pattern - (2, 4) => {} //~ ERROR unreachable pattern + (1, 3) => {} //~ ERROR unreachable pattern + (1, 4) => {} //~ ERROR unreachable pattern + (2, 4) => {} //~ ERROR unreachable pattern (2 | 1, 4) => {} //~ ERROR unreachable pattern (1, 5 | 6) => {} (1, 4 | 5) => {} //~ ERROR unreachable pattern @@ -40,13 +33,13 @@ fn main() { match (Some(0u8),) { (None | Some(1 | 2),) => {} (Some(1),) => {} //~ ERROR unreachable pattern - (None,) => {} //~ ERROR unreachable pattern + (None,) => {} //~ ERROR unreachable pattern _ => {} } match ((0u8,),) { - ((1 | 2,) | (3 | 4,),) => {}, - ((1..=4,),) => {}, //~ ERROR unreachable pattern - _ => {}, + ((1 | 2,) | (3 | 4,),) => {} + ((1..=4,),) => {} //~ ERROR unreachable pattern + _ => {} } match (0,) { diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index 87f69a484bbbc..f16183062ac0f 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -1,110 +1,104 @@ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:16:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:9:9 | LL | (1,) => {} | ^^^^ | note: lint level defined here - --> $DIR/exhaustiveness-unreachable-pattern.rs:4:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:3:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:21:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:14:9 | LL | (2,) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:20:9 | LL | (1 | 2,) => {} | ^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:32:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9 | LL | (1, 3) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:33:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9 | LL | (1, 4) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:34:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9 | LL | (2, 4) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:35:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:28:9 | LL | (2 | 1, 4) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:30:9 | LL | (1, 4 | 5) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:35:9 | LL | (Some(1),) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:36:9 | LL | (None,) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:48:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:41:9 | -LL | ((1..=4,),) => {}, +LL | ((1..=4,),) => {} | ^^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:54:12 + --> $DIR/exhaustiveness-unreachable-pattern.rs:47:12 | LL | | 1,) => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:61:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:54:15 | LL | | 0] => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:59:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:52:15 | LL | | 0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:69:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:62:10 | LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:75:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:68:14 | LL | Some(0 | ^ -error: or-patterns are not fully implemented yet - --> $DIR/exhaustiveness-unreachable-pattern.rs:10:10 - | -LL | (0 | _,) => {} - | ^^^^^ - -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors diff --git a/src/test/ui/or-patterns/feature-gate-const-fn.rs b/src/test/ui/or-patterns/feature-gate-const-fn.rs index d73dcf2666648..2ef5537db60ad 100644 --- a/src/test/ui/or-patterns/feature-gate-const-fn.rs +++ b/src/test/ui/or-patterns/feature-gate-const-fn.rs @@ -1,5 +1,4 @@ #![feature(or_patterns)] -#![allow(incomplete_features)] const fn foo((Ok(a) | Err(a)): Result) { //~^ ERROR or-pattern is not allowed in a `const fn` @@ -31,6 +30,8 @@ fn main() { let x = Ok(3); let Ok(y) | Err(y) = x; //~^ ERROR or-pattern is not allowed in a `const` + //~| ERROR constant contains unimplemented expression type + //~| ERROR constant contains unimplemented expression type 2 }]; } diff --git a/src/test/ui/or-patterns/feature-gate-const-fn.stderr b/src/test/ui/or-patterns/feature-gate-const-fn.stderr index 26143d2f19d33..9284e2d442dfa 100644 --- a/src/test/ui/or-patterns/feature-gate-const-fn.stderr +++ b/src/test/ui/or-patterns/feature-gate-const-fn.stderr @@ -1,5 +1,5 @@ error[E0658]: or-pattern is not allowed in a `const fn` - --> $DIR/feature-gate-const-fn.rs:4:15 + --> $DIR/feature-gate-const-fn.rs:3:15 | LL | const fn foo((Ok(a) | Err(a)): Result) { | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | const fn foo((Ok(a) | Err(a)): Result) { = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: or-pattern is not allowed in a `const fn` - --> $DIR/feature-gate-const-fn.rs:7:9 + --> $DIR/feature-gate-const-fn.rs:6:9 | LL | let Ok(y) | Err(y) = x; | ^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let Ok(y) | Err(y) = x; = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: or-pattern is not allowed in a `const` - --> $DIR/feature-gate-const-fn.rs:13:9 + --> $DIR/feature-gate-const-fn.rs:12:9 | LL | let Ok(y) | Err(y) = x; | ^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | let Ok(y) | Err(y) = x; = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: or-pattern is not allowed in a `static` - --> $DIR/feature-gate-const-fn.rs:19:9 + --> $DIR/feature-gate-const-fn.rs:18:9 | LL | let Ok(y) | Err(y) = x; | ^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | let Ok(y) | Err(y) = x; = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: or-pattern is not allowed in a `static mut` - --> $DIR/feature-gate-const-fn.rs:25:9 + --> $DIR/feature-gate-const-fn.rs:24:9 | LL | let Ok(y) | Err(y) = x; | ^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let Ok(y) | Err(y) = x; = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: or-pattern is not allowed in a `const` - --> $DIR/feature-gate-const-fn.rs:32:13 + --> $DIR/feature-gate-const-fn.rs:31:13 | LL | let Ok(y) | Err(y) = x; | ^^^^^^^^^^^^^^ @@ -52,6 +52,19 @@ LL | let Ok(y) | Err(y) = x; = note: for more information, see https://github.com/rust-lang/rust/issues/49146 = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error: aborting due to 6 previous errors +error[E0019]: constant contains unimplemented expression type + --> $DIR/feature-gate-const-fn.rs:31:25 + | +LL | let Ok(y) | Err(y) = x; + | ^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/feature-gate-const-fn.rs:31:16 + | +LL | let Ok(y) | Err(y) = x; + | ^ + +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/or-patterns/inconsistent-modes.rs b/src/test/ui/or-patterns/inconsistent-modes.rs index 44836893ea2b2..28b5f0c02fef4 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.rs +++ b/src/test/ui/or-patterns/inconsistent-modes.rs @@ -1,8 +1,6 @@ // This test ensures that or patterns require binding mode consistency across arms. #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete - #![allow(non_camel_case_types)] fn main() { // One level: diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr index 0a36ed5548e5b..a34a4fe138753 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.stderr +++ b/src/test/ui/or-patterns/inconsistent-modes.stderr @@ -1,5 +1,5 @@ error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:9:25 + --> $DIR/inconsistent-modes.rs:7:25 | LL | let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); | - ^ bound in different ways @@ -7,7 +7,7 @@ LL | let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); | first binding error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:11:29 + --> $DIR/inconsistent-modes.rs:9:29 | LL | let Ok(ref mut a) | Err(a): Result = Ok(0); | - ^ bound in different ways @@ -15,25 +15,25 @@ LL | let Ok(ref mut a) | Err(a): Result = Ok(0); | first binding error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:13:33 + --> $DIR/inconsistent-modes.rs:11:33 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); | - first binding ^ bound in different ways error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:16:39 + --> $DIR/inconsistent-modes.rs:14:39 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); | - first binding ^ bound in different ways error[E0409]: variable `b` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:16:46 + --> $DIR/inconsistent-modes.rs:14:46 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); | - first binding ^ bound in different ways error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:22:38 + --> $DIR/inconsistent-modes.rs:20:38 | LL | let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); | - ^ bound in different ways @@ -41,23 +41,15 @@ LL | let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); | first binding error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:26:34 + --> $DIR/inconsistent-modes.rs:24:34 | LL | let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1); | - ^ bound in different ways | | | first binding -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/inconsistent-modes.rs:3:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0308]: mismatched types - --> $DIR/inconsistent-modes.rs:13:25 + --> $DIR/inconsistent-modes.rs:11:25 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); | ^^^^^^^^^ types differ in mutability @@ -66,7 +58,7 @@ LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); found type `&mut &mut u8` error[E0308]: mismatched types - --> $DIR/inconsistent-modes.rs:16:31 + --> $DIR/inconsistent-modes.rs:14:31 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); | ^^^^^^^^^ types differ in mutability diff --git a/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs b/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs new file mode 100644 index 0000000000000..0c2ae44e546d9 --- /dev/null +++ b/src/test/ui/or-patterns/issue-67514-irrefutable-param.rs @@ -0,0 +1,11 @@ +// Check that we don't ICE for irrefutable or-patterns in function parameters + +// check-pass + +#![feature(or_patterns)] + +fn foo((Some(_) | None): Option) {} + +fn main() { + foo(None); +} diff --git a/src/test/ui/or-patterns/let-pattern.rs b/src/test/ui/or-patterns/let-pattern.rs new file mode 100644 index 0000000000000..07e37412ce842 --- /dev/null +++ b/src/test/ui/or-patterns/let-pattern.rs @@ -0,0 +1,19 @@ +#![feature(or_patterns)] + +// run-pass + +fn or_pat_let(x: Result) -> u32 { + let Ok(y) | Err(y) = x; + y +} + +fn or_pat_arg((Ok(y) | Err(y)): Result) -> u32 { + y +} + +fn main() { + assert_eq!(or_pat_let(Ok(3)), 3); + assert_eq!(or_pat_let(Err(5)), 5); + assert_eq!(or_pat_arg(Ok(7)), 7); + assert_eq!(or_pat_arg(Err(9)), 9); +} diff --git a/src/test/ui/or-patterns/missing-bindings.rs b/src/test/ui/or-patterns/missing-bindings.rs index b065028e7a5a4..67cf52fa8c418 100644 --- a/src/test/ui/or-patterns/missing-bindings.rs +++ b/src/test/ui/or-patterns/missing-bindings.rs @@ -3,8 +3,6 @@ // edition:2018 #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete - #![allow(non_camel_case_types)] fn main() {} diff --git a/src/test/ui/or-patterns/missing-bindings.stderr b/src/test/ui/or-patterns/missing-bindings.stderr index c73af7a42eec0..57270e4412351 100644 --- a/src/test/ui/or-patterns/missing-bindings.stderr +++ b/src/test/ui/or-patterns/missing-bindings.stderr @@ -1,5 +1,5 @@ error[E0408]: variable `beta` is not bound in all patterns - --> $DIR/missing-bindings.rs:22:9 + --> $DIR/missing-bindings.rs:20:9 | LL | let alpha | beta | charlie = alpha; | ^^^^^ ---- ^^^^^^^ pattern doesn't bind `beta` @@ -8,7 +8,7 @@ LL | let alpha | beta | charlie = alpha; | pattern doesn't bind `beta` error[E0408]: variable `beta` is not bound in all patterns - --> $DIR/missing-bindings.rs:24:14 + --> $DIR/missing-bindings.rs:22:14 | LL | Some(alpha | beta) => {} | ^^^^^ ---- variable not in all patterns @@ -16,7 +16,7 @@ LL | Some(alpha | beta) => {} | pattern doesn't bind `beta` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:36:19 + --> $DIR/missing-bindings.rs:34:19 | LL | let A(a, _) | _ = X; | - ^ pattern doesn't bind `a` @@ -24,7 +24,7 @@ LL | let A(a, _) | _ = X; | variable not in all patterns error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:37:9 + --> $DIR/missing-bindings.rs:35:9 | LL | let _ | B(a) = X; | ^ - variable not in all patterns @@ -32,7 +32,7 @@ LL | let _ | B(a) = X; | pattern doesn't bind `a` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:38:9 + --> $DIR/missing-bindings.rs:36:9 | LL | let A(..) | B(a) = X; | ^^^^^ - variable not in all patterns @@ -40,7 +40,7 @@ LL | let A(..) | B(a) = X; | pattern doesn't bind `a` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:39:19 + --> $DIR/missing-bindings.rs:37:19 | LL | let A(a, _) | B(_) = X; | - ^^^^ pattern doesn't bind `a` @@ -48,7 +48,7 @@ LL | let A(a, _) | B(_) = X; | variable not in all patterns error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:40:19 + --> $DIR/missing-bindings.rs:38:19 | LL | let A(_, a) | B(_) = X; | - ^^^^ pattern doesn't bind `a` @@ -56,7 +56,7 @@ LL | let A(_, a) | B(_) = X; | variable not in all patterns error[E0408]: variable `b` is not bound in all patterns - --> $DIR/missing-bindings.rs:41:19 + --> $DIR/missing-bindings.rs:39:19 | LL | let A(a, b) | B(a) = X; | - ^^^^ pattern doesn't bind `b` @@ -64,7 +64,7 @@ LL | let A(a, b) | B(a) = X; | variable not in all patterns error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:45:9 + --> $DIR/missing-bindings.rs:43:9 | LL | let A(A(..) | B(_), _) | B(a) = Y; | ^^^^^^^^^^^^^^^^^^ - variable not in all patterns @@ -72,7 +72,7 @@ LL | let A(A(..) | B(_), _) | B(a) = Y; | pattern doesn't bind `a` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:46:11 + --> $DIR/missing-bindings.rs:44:11 | LL | let A(A(..) | B(a), _) | B(A(a, _) | B(a)) = Y; | ^^^^^ - variable not in all patterns @@ -80,7 +80,7 @@ LL | let A(A(..) | B(a), _) | B(A(a, _) | B(a)) = Y; | pattern doesn't bind `a` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:21 + --> $DIR/missing-bindings.rs:46:21 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | - ^^^^ pattern doesn't bind `a` @@ -88,7 +88,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | variable not in all patterns error[E0408]: variable `b` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:21 + --> $DIR/missing-bindings.rs:46:21 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | - ^^^^ pattern doesn't bind `b` @@ -96,7 +96,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | variable not in all patterns error[E0408]: variable `c` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:11 + --> $DIR/missing-bindings.rs:46:11 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | ^^^^^^^ - variable not in all patterns @@ -104,7 +104,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | pattern doesn't bind `c` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:32 + --> $DIR/missing-bindings.rs:46:32 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | - ^^^^ pattern doesn't bind `a` @@ -112,7 +112,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | variable not in all patterns error[E0408]: variable `b` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:32 + --> $DIR/missing-bindings.rs:46:32 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | - ^^^^ pattern doesn't bind `b` @@ -120,7 +120,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | variable not in all patterns error[E0408]: variable `c` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:32 + --> $DIR/missing-bindings.rs:46:32 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | - ^^^^ pattern doesn't bind `c` @@ -128,7 +128,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | variable not in all patterns error[E0408]: variable `d` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:32 + --> $DIR/missing-bindings.rs:46:32 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | - ^^^^ pattern doesn't bind `d` @@ -136,7 +136,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | variable not in all patterns error[E0408]: variable `e` is not bound in all patterns - --> $DIR/missing-bindings.rs:48:9 + --> $DIR/missing-bindings.rs:46:9 | LL | let A(A(a, b) | B(c), d) | B(e) = Y; | ^^^^^^^^^^^^^^^^^^^^ - variable not in all patterns @@ -144,7 +144,7 @@ LL | let A(A(a, b) | B(c), d) | B(e) = Y; | pattern doesn't bind `e` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:64:29 + --> $DIR/missing-bindings.rs:62:29 | LL | Ok(a) | Err(_), | - ^^^^^^ pattern doesn't bind `a` @@ -152,7 +152,7 @@ LL | Ok(a) | Err(_), | variable not in all patterns error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:72:21 + --> $DIR/missing-bindings.rs:70:21 | LL | A(_, a) | | - variable not in all patterns @@ -160,7 +160,7 @@ LL | B(b), | ^^^^ pattern doesn't bind `a` error[E0408]: variable `b` is not bound in all patterns - --> $DIR/missing-bindings.rs:71:21 + --> $DIR/missing-bindings.rs:69:21 | LL | A(_, a) | | ^^^^^^^ pattern doesn't bind `b` @@ -168,7 +168,7 @@ LL | B(b), | - variable not in all patterns error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:75:17 + --> $DIR/missing-bindings.rs:73:17 | LL | A(_, a) | | - variable not in all patterns @@ -177,7 +177,7 @@ LL | B(_) | ^^^^ pattern doesn't bind `a` error[E0408]: variable `b` is not bound in all patterns - --> $DIR/missing-bindings.rs:75:17 + --> $DIR/missing-bindings.rs:73:17 | LL | B(b), | - variable not in all patterns @@ -186,7 +186,7 @@ LL | B(_) | ^^^^ pattern doesn't bind `b` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/missing-bindings.rs:79:13 + --> $DIR/missing-bindings.rs:77:13 | LL | B(Ok(a) | Err(a)) | - variable not in all patterns @@ -198,7 +198,7 @@ LL | V3(c), | ^^^^^ pattern doesn't bind `a` error[E0408]: variable `b` is not bound in all patterns - --> $DIR/missing-bindings.rs:60:13 + --> $DIR/missing-bindings.rs:58:13 | LL | / V1( LL | | @@ -216,7 +216,7 @@ LL | V3(c), | ^^^^^ pattern doesn't bind `b` error[E0408]: variable `c` is not bound in all patterns - --> $DIR/missing-bindings.rs:60:13 + --> $DIR/missing-bindings.rs:58:13 | LL | / V1( LL | | @@ -237,14 +237,6 @@ LL | | ) | LL | V3(c), | - variable not in all patterns -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/missing-bindings.rs:5:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error: aborting due to 26 previous errors For more information about this error, try `rustc --explain E0408`. diff --git a/src/test/ui/or-patterns/mix-with-wild.rs b/src/test/ui/or-patterns/mix-with-wild.rs new file mode 100644 index 0000000000000..37f20df1b312d --- /dev/null +++ b/src/test/ui/or-patterns/mix-with-wild.rs @@ -0,0 +1,19 @@ +// Test that an or-pattern works with a wild pattern. This tests two things: +// +// 1) The Wild pattern should cause the pattern to always succeed. +// 2) or-patterns should work with simplifyable patterns. + +// run-pass +#![feature(or_patterns)] + +pub fn test(x: Option) -> bool { + match x { + Some(0 | _) => true, + _ => false, + } +} + +fn main() { + assert!(test(Some(42))); + assert!(!test(None)); +} diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs index e308c0adb4eb8..702c9573741e7 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.rs +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -1,5 +1,4 @@ #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash fn main() { let x = 3; diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index c71c760b1e303..cb32068ec0d5e 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -1,5 +1,5 @@ error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:8:15 + --> $DIR/multiple-pattern-typo.rs:7:15 | LL | 1 | 2 || 3 => (), | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` @@ -7,7 +7,7 @@ LL | 1 | 2 || 3 => (), | while parsing this or-pattern starting here error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:13:16 + --> $DIR/multiple-pattern-typo.rs:12:16 | LL | (1 | 2 || 3) => (), | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` @@ -15,7 +15,7 @@ LL | (1 | 2 || 3) => (), | while parsing this or-pattern starting here error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:18:16 + --> $DIR/multiple-pattern-typo.rs:17:16 | LL | (1 | 2 || 3,) => (), | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` @@ -23,7 +23,7 @@ LL | (1 | 2 || 3,) => (), | while parsing this or-pattern starting here error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:25:18 + --> $DIR/multiple-pattern-typo.rs:24:18 | LL | TS(1 | 2 || 3) => (), | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` @@ -31,7 +31,7 @@ LL | TS(1 | 2 || 3) => (), | while parsing this or-pattern starting here error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:32:23 + --> $DIR/multiple-pattern-typo.rs:31:23 | LL | NS { f: 1 | 2 || 3 } => (), | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` @@ -39,7 +39,7 @@ LL | NS { f: 1 | 2 || 3 } => (), | while parsing this or-pattern starting here error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:37:16 + --> $DIR/multiple-pattern-typo.rs:36:16 | LL | [1 | 2 || 3] => (), | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` @@ -47,18 +47,10 @@ LL | [1 | 2 || 3] => (), | while parsing this or-pattern starting here error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:42:9 + --> $DIR/multiple-pattern-typo.rs:41:9 | LL | || 1 | 2 | 3 => (), | ^^ help: use a single `|` to separate multiple alternative patterns: `|` -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/multiple-pattern-typo.rs:1:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error: aborting due to 7 previous errors diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs index ce6836f30f946..d23220056524b 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -2,7 +2,6 @@ // This is not a semantic test. We only test parsing. #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash fn main() {} diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index e77d92e8b07d9..6cbb59dc22031 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -1,53 +1,53 @@ error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:28:13 + --> $DIR/or-patterns-syntactic-fail.rs:27:13 | LL | fn fun1(A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is not allowed in a parameter pattern - --> $DIR/or-patterns-syntactic-fail.rs:30:13 + --> $DIR/or-patterns-syntactic-fail.rs:29:13 | LL | fn fun2(| A | B: E) {} | ^ help: remove the `|` error: an or-pattern parameter must be wrapped in parenthesis - --> $DIR/or-patterns-syntactic-fail.rs:30:15 + --> $DIR/or-patterns-syntactic-fail.rs:29:15 | LL | fn fun2(| A | B: E) {} | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:41:11 + --> $DIR/or-patterns-syntactic-fail.rs:40:11 | LL | let ( | A | B) = E::A; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:42:11 + --> $DIR/or-patterns-syntactic-fail.rs:41:11 | LL | let ( | A | B,) = (E::B,); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:43:11 + --> $DIR/or-patterns-syntactic-fail.rs:42:11 | LL | let [ | A | B ] = [E::A]; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:44:13 + --> $DIR/or-patterns-syntactic-fail.rs:43:13 | LL | let TS( | A | B ); | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:45:17 + --> $DIR/or-patterns-syntactic-fail.rs:44:17 | LL | let NS { f: | A | B }; | ^ help: remove the `|` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:47:11 + --> $DIR/or-patterns-syntactic-fail.rs:46:11 | LL | let ( || A | B) = E::A; | ^^ help: remove the `||` @@ -55,7 +55,7 @@ LL | let ( || A | B) = E::A; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:48:11 + --> $DIR/or-patterns-syntactic-fail.rs:47:11 | LL | let [ || A | B ] = [E::A]; | ^^ help: remove the `||` @@ -63,7 +63,7 @@ LL | let [ || A | B ] = [E::A]; = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:49:13 + --> $DIR/or-patterns-syntactic-fail.rs:48:13 | LL | let TS( || A | B ); | ^^ help: remove the `||` @@ -71,7 +71,7 @@ LL | let TS( || A | B ); = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern - --> $DIR/or-patterns-syntactic-fail.rs:50:17 + --> $DIR/or-patterns-syntactic-fail.rs:49:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` @@ -79,7 +79,7 @@ LL | let NS { f: || A | B }; = note: alternatives in or-patterns are separated with `|`, not `||` error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:14:15 + --> $DIR/or-patterns-syntactic-fail.rs:13:15 | LL | macro_rules! accept_pat { | ----------------------- when calling this macro @@ -88,7 +88,7 @@ LL | accept_pat!(p | q); | ^ no rules expected this token in macro call error: no rules expected the token `|` - --> $DIR/or-patterns-syntactic-fail.rs:15:13 + --> $DIR/or-patterns-syntactic-fail.rs:14:13 | LL | macro_rules! accept_pat { | ----------------------- when calling this macro @@ -96,16 +96,8 @@ LL | macro_rules! accept_pat { LL | accept_pat!(| p | q); | ^ no rules expected this token in macro call -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/or-patterns-syntactic-fail.rs:4:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0369]: no implementation for `E | ()` - --> $DIR/or-patterns-syntactic-fail.rs:24:22 + --> $DIR/or-patterns-syntactic-fail.rs:23:22 | LL | let _ = |A | B: E| (); | ----^ -- () @@ -115,7 +107,7 @@ LL | let _ = |A | B: E| (); = note: an implementation of `std::ops::BitOr` might be missing for `E` error[E0308]: mismatched types - --> $DIR/or-patterns-syntactic-fail.rs:52:36 + --> $DIR/or-patterns-syntactic-fail.rs:51:36 | LL | let recovery_witness: String = 0; | ------ ^ diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs index 73c1477c281a8..5fe72caf9c1ff 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -3,7 +3,7 @@ // check-pass -#![feature(or_patterns)] //~ WARNING the feature `or_patterns` is incomplete +#![feature(or_patterns)] fn main() {} diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr deleted file mode 100644 index 3145a2e9f2a6e..0000000000000 --- a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/or-patterns-syntactic-pass.rs:6:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - diff --git a/src/test/ui/or-patterns/search-via-bindings.rs b/src/test/ui/or-patterns/search-via-bindings.rs new file mode 100644 index 0000000000000..fb3d8c2cb3ef2 --- /dev/null +++ b/src/test/ui/or-patterns/search-via-bindings.rs @@ -0,0 +1,33 @@ +// Check that we expand multiple or-patterns from left to right. + +// run-pass + +#![feature(or_patterns)] +#![allow(unreachable_patterns)] // FIXME(or-patterns) this shouldn't trigger + +fn search(target: (bool, bool, bool)) -> u32 { + let x = ((false, true), (false, true), (false, true)); + let mut guard_count = 0; + match x { + ((a, _) | (_, a), (b @ _, _) | (_, b @ _), (c @ false, _) | (_, c @ true)) + if { + guard_count += 1; + (a, b, c) == target + } => + { + guard_count + } + _ => unreachable!(), + } +} + +fn main() { + assert_eq!(search((false, false, false)), 1); + assert_eq!(search((false, false, true)), 2); + assert_eq!(search((false, true, false)), 3); + assert_eq!(search((false, true, true)), 4); + assert_eq!(search((true, false, false)), 5); + assert_eq!(search((true, false, true)), 6); + assert_eq!(search((true, true, false)), 7); + assert_eq!(search((true, true, true)), 8); +} diff --git a/src/test/ui/or-patterns/struct-like.rs b/src/test/ui/or-patterns/struct-like.rs new file mode 100644 index 0000000000000..3794a8b6c1510 --- /dev/null +++ b/src/test/ui/or-patterns/struct-like.rs @@ -0,0 +1,42 @@ +// run-pass + +#![feature(or_patterns)] + +#[derive(Debug)] +enum Other { + One, + Two, + Three, +} + +#[derive(Debug)] +enum Test { + Foo { first: usize, second: usize }, + Bar { other: Option }, + Baz, +} + +fn test(x: Option) -> bool { + match x { + Some( + Test::Foo { first: 1024 | 2048, second: 2048 | 4096 } + | Test::Bar { other: Some(Other::One | Other::Two) }, + ) => true, + // wild case + Some(_) => false, + // empty case + None => false, + } +} + +fn main() { + assert!(test(Some(Test::Foo { first: 1024, second: 4096 }))); + assert!(!test(Some(Test::Foo { first: 2048, second: 8192 }))); + assert!(!test(Some(Test::Foo { first: 42, second: 2048 }))); + assert!(test(Some(Test::Bar { other: Some(Other::One) }))); + assert!(test(Some(Test::Bar { other: Some(Other::Two) }))); + assert!(!test(Some(Test::Bar { other: Some(Other::Three) }))); + assert!(!test(Some(Test::Bar { other: None }))); + assert!(!test(Some(Test::Baz))); + assert!(!test(None)); +} diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs index 89ea2d5181945..e8b5b492b7738 100644 --- a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs +++ b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs @@ -3,7 +3,6 @@ #![feature(bindings_after_at)] #![feature(or_patterns)] -//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash fn main() { fn f(a @ a @ a: ()) {} diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr index c568d2a3aa2b8..cba17d82e93c5 100644 --- a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr +++ b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr @@ -1,71 +1,63 @@ error[E0415]: identifier `a` is bound more than once in this parameter list - --> $DIR/pat-at-same-name-both.rs:9:14 + --> $DIR/pat-at-same-name-both.rs:8:14 | LL | fn f(a @ a @ a: ()) {} | ^ used as parameter more than once error[E0415]: identifier `a` is bound more than once in this parameter list - --> $DIR/pat-at-same-name-both.rs:9:18 + --> $DIR/pat-at-same-name-both.rs:8:18 | LL | fn f(a @ a @ a: ()) {} | ^ used as parameter more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:14:20 + --> $DIR/pat-at-same-name-both.rs:13:20 | LL | Ok(a @ b @ a) | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:16:23 + --> $DIR/pat-at-same-name-both.rs:15:23 | LL | | Err(a @ b @ a) | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:21:13 + --> $DIR/pat-at-same-name-both.rs:20:13 | LL | let a @ a @ a = (); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:21:17 + --> $DIR/pat-at-same-name-both.rs:20:17 | LL | let a @ a @ a = (); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:24:21 + --> $DIR/pat-at-same-name-both.rs:23:21 | LL | let ref a @ ref a = (); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:26:29 + --> $DIR/pat-at-same-name-both.rs:25:29 | LL | let ref mut a @ ref mut a = (); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:29:17 + --> $DIR/pat-at-same-name-both.rs:28:17 | LL | let a @ (Ok(a) | Err(a)) = Ok(()); | ^ used in a pattern more than once error[E0416]: identifier `a` is bound more than once in the same pattern - --> $DIR/pat-at-same-name-both.rs:29:26 + --> $DIR/pat-at-same-name-both.rs:28:26 | LL | let a @ (Ok(a) | Err(a)) = Ok(()); | ^ used in a pattern more than once -warning: the feature `or_patterns` is incomplete and may cause the compiler to crash - --> $DIR/pat-at-same-name-both.rs:5:12 - | -LL | #![feature(or_patterns)] - | ^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error: aborting due to 10 previous errors Some errors have detailed explanations: E0415, E0416. diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs b/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs index f6b317886bfad..4489303638358 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs @@ -6,7 +6,6 @@ fn foo(res: Result) -> u32 { let Ok(x) = res; //~^ ERROR refutable pattern x - //~^ ERROR use of possibly-uninitialized variable: `x` } fn main() { diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr index f9ae75b18317d..aa23aed4b425a 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -11,13 +11,6 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | if let Ok(x) = res { /* */ } | -error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/recursive-types-are-not-uninhabited.rs:8:5 - | -LL | x - | ^ use of possibly-uninitialized `x` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0005, E0381. -For more information about an error, try `rustc --explain E0005`. +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr index 1f1211aa198f8..612fae208cc9d 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr @@ -65,13 +65,18 @@ LL | match &(e.clone(), e.clone()) { | ^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | &(Either::One(_t), Either::Two(_u)) - | ----------------------------------- - | | | | - | | | ...and here - | | data moved here - | help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))` + | -- -- ...and here + | | + | data moved here | = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the `&` + | +LL | (Either::One(_t), Either::Two(_u)) +LL | +LL | +LL | | &(Either::Two(_t), Either::One(_u)) => (), + | error[E0507]: cannot move out of a shared reference --> $DIR/duplicate-suggestions.rs:70:11 @@ -170,13 +175,18 @@ LL | match &mut (em.clone(), em.clone()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | &mut (Either::One(_t), Either::Two(_u)) - | --------------------------------------- - | | | | - | | | ...and here - | | data moved here - | help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))` + | -- -- ...and here + | | + | data moved here | = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the `&mut` + | +LL | (Either::One(_t), Either::Two(_u)) +LL | +LL | +LL | | &mut (Either::Two(_t), Either::One(_u)) => (), + | error[E0507]: cannot move out of a mutable reference --> $DIR/duplicate-suggestions.rs:122:11 diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr index ac91ac43736f9..5550e097cf554 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr @@ -263,11 +263,18 @@ LL | match r { | ^ LL | LL | &Either::One(_t) - | ---------------- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait - | help: consider removing the `&`: `Either::One(_t)` + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | +help: consider removing the `&` + | +LL | Either::One(_t) +LL | +LL | +LL | | &Either::Two(_t) => (), + | error[E0507]: cannot move out of `r.0` which is behind a shared reference --> $DIR/simple.rs:188:11 @@ -502,11 +509,18 @@ LL | match &e { | ^^ LL | LL | &Either::One(_t) - | ---------------- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait - | help: consider removing the `&`: `Either::One(_t)` + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | +help: consider removing the `&` + | +LL | Either::One(_t) +LL | +LL | +LL | | &Either::Two(_t) => (), + | error[E0507]: cannot move out of a shared reference --> $DIR/simple.rs:308:11 @@ -571,11 +585,18 @@ LL | match &mut em { | ^^^^^^^ LL | LL | &mut Either::One(_t) - | -------------------- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait - | help: consider removing the `&mut`: `Either::One(_t)` + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait + | +help: consider removing the `&mut` + | +LL | Either::One(_t) +LL | +LL | +LL | | &mut Either::Two(_t) => (), + | error[E0507]: cannot move out of a mutable reference --> $DIR/simple.rs:343:11