Handle reinits in match guards

This commit is contained in:
Eric Holk 2021-12-16 12:07:36 -08:00
parent 2af02cf2c4
commit 4a70de7932
3 changed files with 47 additions and 8 deletions

View File

@ -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::<Vec<_>>();
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)
});

View File

@ -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;

View File

@ -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
}