Skip to content

Commit 06d5a96

Browse files
committed
Support break and continue with block targets
Issue rust-lang#93197
1 parent f77a407 commit 06d5a96

File tree

1 file changed

+44
-2
lines changed
  • compiler/rustc_typeck/src/check/generator_interior/drop_ranges

1 file changed

+44
-2
lines changed

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

+44-2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,45 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
209209
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
210210
}
211211
}
212+
213+
/// Break and continue expression targets might be another expression or a block,
214+
/// but this analysis only looks at expressions. In case a break has a block as a
215+
/// target, this will find the last expression in the block and return its HirId
216+
/// instead.
217+
fn find_target_expression(&self, hir_id: HirId) -> HirId {
218+
let node = self.hir.get(hir_id);
219+
match node {
220+
hir::Node::Expr(_) => hir_id,
221+
hir::Node::Block(b) => b.expr.map_or_else(
222+
// If there is no tail expression, there will be at least one statement in the
223+
// block because the block contains a break or continue statement.
224+
|| b.stmts.last().unwrap().hir_id,
225+
|expr| expr.hir_id,
226+
),
227+
hir::Node::Param(..)
228+
| hir::Node::Item(..)
229+
| hir::Node::ForeignItem(..)
230+
| hir::Node::TraitItem(..)
231+
| hir::Node::ImplItem(..)
232+
| hir::Node::Variant(..)
233+
| hir::Node::Field(..)
234+
| hir::Node::AnonConst(..)
235+
| hir::Node::Stmt(..)
236+
| hir::Node::PathSegment(..)
237+
| hir::Node::Ty(..)
238+
| hir::Node::TraitRef(..)
239+
| hir::Node::Binding(..)
240+
| hir::Node::Pat(..)
241+
| hir::Node::Arm(..)
242+
| hir::Node::Local(..)
243+
| hir::Node::Ctor(..)
244+
| hir::Node::Lifetime(..)
245+
| hir::Node::GenericParam(..)
246+
| hir::Node::Visibility(..)
247+
| hir::Node::Crate(..)
248+
| hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node),
249+
}
250+
}
212251
}
213252

214253
impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
@@ -334,7 +373,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
334373
}
335374
ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..)
336375
| ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => {
337-
self.drop_ranges.add_control_edge_hir_id(self.expr_index, target);
376+
self.drop_ranges
377+
.add_control_edge_hir_id(self.expr_index, self.find_target_expression(target));
338378
}
339379

340380
ExprKind::Call(f, args) => {
@@ -462,11 +502,13 @@ impl DropRangesBuilder {
462502
/// Should be called after visiting the HIR but before solving the control flow, otherwise some
463503
/// edges will be missed.
464504
fn process_deferred_edges(&mut self) {
505+
trace!("processing deferred edges. post_order_map={:#?}", self.post_order_map);
465506
let mut edges = vec![];
466507
swap(&mut edges, &mut self.deferred_edges);
467508
edges.into_iter().for_each(|(from, to)| {
468-
let to = *self.post_order_map.get(&to).expect("Expression ID not found");
469509
trace!("Adding deferred edge from {:?} to {:?}", from, to);
510+
let to = *self.post_order_map.get(&to).expect("Expression ID not found");
511+
trace!("target edge PostOrderId={:?}", to);
470512
self.add_control_edge(from, to)
471513
});
472514
}

0 commit comments

Comments
 (0)