diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index 32f423f3bfe..0520931d5f6 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -133,11 +133,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { ExprKind::Match(scrutinee, arms, ..) => { self.visit_expr(scrutinee); - let fork = self.expr_index; - let arm_end_ids = arms - .iter() - .map(|hir::Arm { pat, body, guard, .. }| { - self.drop_ranges.add_control_edge(fork, self.expr_index + 1); + let (guard_exit, arm_end_ids) = arms.iter().fold( + (self.expr_index, vec![]), + |(incoming_edge, mut arm_end_ids), hir::Arm { pat, body, guard, .. }| { + self.drop_ranges.add_control_edge(incoming_edge, self.expr_index + 1); self.visit_pat(pat); match guard { Some(Guard::If(expr)) => self.visit_expr(expr), @@ -147,10 +146,16 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { } None => (), } + let to_next_arm = self.expr_index; + // The default edge does not get added since we also have an explicit edge, + // so we also need to add an edge to the next node as well. + self.drop_ranges.add_control_edge(self.expr_index, self.expr_index + 1); self.visit_expr(body); - self.expr_index - }) - .collect::>(); + arm_end_ids.push(self.expr_index); + (to_next_arm, arm_end_ids) + }, + ); + self.drop_ranges.add_control_edge(guard_exit, self.expr_index + 1); arm_end_ids.into_iter().for_each(|arm_end| { self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1) }); diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs index b87b3dd9a5f..20aad7aedf7 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs @@ -5,6 +5,15 @@ use super::{DropRangesBuilder, PostOrderId}; +/// Writes the CFG for DropRangesBuilder to a .dot file for visualization. +/// +/// It is not normally called, but is kept around to easily add debugging +/// code when needed. +#[allow(dead_code)] +pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) { + dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap(); +} + impl<'a> dot::GraphWalk<'a> for DropRangesBuilder { type Node = PostOrderId; diff --git a/src/test/ui/generator/reinit-in-match-guard.rs b/src/test/ui/generator/reinit-in-match-guard.rs new file mode 100644 index 00000000000..260b341a525 --- /dev/null +++ b/src/test/ui/generator/reinit-in-match-guard.rs @@ -0,0 +1,25 @@ +// build-pass + +#![feature(generators)] + +#![allow(unused_assignments, dead_code)] + +fn main() { + let _ = || { + let mut x = vec![22_usize]; + std::mem::drop(x); + match y() { + true if { + x = vec![]; + false + } => {} + _ => { + yield; + } + } + }; +} + +fn y() -> bool { + true +}