Skip to content

Commit 4a70de7

Browse files
committed
Handle reinits in match guards
1 parent 2af02cf commit 4a70de7

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,10 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
133133
ExprKind::Match(scrutinee, arms, ..) => {
134134
self.visit_expr(scrutinee);
135135

136-
let fork = self.expr_index;
137-
let arm_end_ids = arms
138-
.iter()
139-
.map(|hir::Arm { pat, body, guard, .. }| {
140-
self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
136+
let (guard_exit, arm_end_ids) = arms.iter().fold(
137+
(self.expr_index, vec![]),
138+
|(incoming_edge, mut arm_end_ids), hir::Arm { pat, body, guard, .. }| {
139+
self.drop_ranges.add_control_edge(incoming_edge, self.expr_index + 1);
141140
self.visit_pat(pat);
142141
match guard {
143142
Some(Guard::If(expr)) => self.visit_expr(expr),
@@ -147,10 +146,16 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
147146
}
148147
None => (),
149148
}
149+
let to_next_arm = self.expr_index;
150+
// The default edge does not get added since we also have an explicit edge,
151+
// so we also need to add an edge to the next node as well.
152+
self.drop_ranges.add_control_edge(self.expr_index, self.expr_index + 1);
150153
self.visit_expr(body);
151-
self.expr_index
152-
})
153-
.collect::<Vec<_>>();
154+
arm_end_ids.push(self.expr_index);
155+
(to_next_arm, arm_end_ids)
156+
},
157+
);
158+
self.drop_ranges.add_control_edge(guard_exit, self.expr_index + 1);
154159
arm_end_ids.into_iter().for_each(|arm_end| {
155160
self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1)
156161
});

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ use rustc_graphviz as dot;
55

66
use super::{DropRangesBuilder, PostOrderId};
77

8+
/// Writes the CFG for DropRangesBuilder to a .dot file for visualization.
9+
///
10+
/// It is not normally called, but is kept around to easily add debugging
11+
/// code when needed.
12+
#[allow(dead_code)]
13+
pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
14+
dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
15+
}
16+
817
impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
918
type Node = PostOrderId;
1019

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// build-pass
2+
3+
#![feature(generators)]
4+
5+
#![allow(unused_assignments, dead_code)]
6+
7+
fn main() {
8+
let _ = || {
9+
let mut x = vec![22_usize];
10+
std::mem::drop(x);
11+
match y() {
12+
true if {
13+
x = vec![];
14+
false
15+
} => {}
16+
_ => {
17+
yield;
18+
}
19+
}
20+
};
21+
}
22+
23+
fn y() -> bool {
24+
true
25+
}

0 commit comments

Comments
 (0)