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 =
+ let mut candidates =
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
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,
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
// This will generate code to test scrutinee_place and
// branch to the appropriate arm block
- self.match_candidates(
- scrutinee_span,
- block,
- &mut otherwise,
- &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);
let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
- for candidate in candidates.into_iter() {
+ 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;
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 {
guard: Option<(&Guard<'tcx>, region::Scope)>,
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
scrutinee_span: Span,
- arm_scope: region::Scope,
+ arm_scope: Option<region::Scope>,
) -> BasicBlock {
if candidate.subcandidates.is_empty() {
// Avoid generating another `BasicBlock` when we only have one
guard,
fake_borrow_temps,
scrutinee_span,
+ true,
)
} else {
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.
candidate,
&mut Vec::new(),
&mut |leaf_candidate, parent_bindings| {
- self.clear_top_scope(arm_scope);
+ 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| {
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);
- } 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);
+ } 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
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);
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 {
// that we have to inspect before we bind them.)
self.bind_matched_candidate_for_arm_body(
block,
+ schedule_drops,
parent_bindings
.iter()
.flat_map(|(bindings, _)| bindings)
fn bind_matched_candidate_for_arm_body<'b>(
&mut self,
block: BasicBlock,
+ schedule_drops: bool,
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
) where
'tcx: 'b,
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()))