Skip to content

Commit bdc37aa

Browse files
mir: Add TerminatorKind::FalseUnwind
Sometimes a simple goto misses the cleanup/unwind edges. Specifically, in the case of infinite loops such as those introduced by a loop statement without any other out edges. Analogous to TerminatorKind::FalseEdges; this new terminator kind is used when we want borrowck to consider an unwind path, but real control flow should never actually take it.
1 parent 5ca88ae commit bdc37aa

File tree

19 files changed

+97
-18
lines changed

19 files changed

+97
-18
lines changed

src/librustc/ich/impls_mir.rs

+4
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ for mir::TerminatorKind<'gcx> {
201201
target.hash_stable(hcx, hasher);
202202
}
203203
}
204+
mir::TerminatorKind::FalseUnwind { ref real_target, ref unwind } => {
205+
real_target.hash_stable(hcx, hasher);
206+
unwind.hash_stable(hcx, hasher);
207+
}
204208
}
205209
}
206210
}

src/librustc/mir/mod.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -803,9 +803,28 @@ pub enum TerminatorKind<'tcx> {
803803
/// Indicates the end of the dropping of a generator
804804
GeneratorDrop,
805805

806+
/// A block where control flow only ever takes one real path, but borrowck
807+
/// needs to be more conservative.
806808
FalseEdges {
809+
/// The target normal control flow will take
807810
real_target: BasicBlock,
808-
imaginary_targets: Vec<BasicBlock>
811+
/// The list of blocks control flow could conceptually take, but won't
812+
/// in practice
813+
imaginary_targets: Vec<BasicBlock>,
814+
},
815+
/// A terminator for blocks that only take one path in reality, but where we
816+
/// reserve the right to unwind in borrowck, even if it won't happen in practice.
817+
/// This can arise in infinite loops with no function calls for example.
818+
FalseUnwind {
819+
/// The target normal control flow will take
820+
real_target: BasicBlock,
821+
/// The imaginary cleanup block link. This particular path will never be taken
822+
/// in practice, but in order to avoid fragility we want to always
823+
/// consider it in borrowck. We don't want to accept programs which
824+
/// pass borrowck only when panic=abort or some assertions are disabled
825+
/// due to release vs. debug mode builds. This needs to be an Option because
826+
/// of the remove_noop_landing_pads and no_landing_pads passes
827+
unwind: Option<BasicBlock>,
809828
},
810829
}
811830

@@ -865,6 +884,8 @@ impl<'tcx> TerminatorKind<'tcx> {
865884
s.extend_from_slice(imaginary_targets);
866885
s.into_cow()
867886
}
887+
FalseUnwind { real_target: t, unwind: Some(u) } => vec![t, u].into_cow(),
888+
FalseUnwind { real_target: ref t, unwind: None } => slice::from_ref(t).into_cow(),
868889
}
869890
}
870891

@@ -897,6 +918,8 @@ impl<'tcx> TerminatorKind<'tcx> {
897918
s.extend(imaginary_targets.iter_mut());
898919
s
899920
}
921+
FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => vec![t, u],
922+
FalseUnwind { ref mut real_target, unwind: None } => vec![real_target],
900923
}
901924
}
902925

@@ -916,7 +939,8 @@ impl<'tcx> TerminatorKind<'tcx> {
916939
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
917940
TerminatorKind::Assert { cleanup: ref mut unwind, .. } |
918941
TerminatorKind::DropAndReplace { ref mut unwind, .. } |
919-
TerminatorKind::Drop { ref mut unwind, .. } => {
942+
TerminatorKind::Drop { ref mut unwind, .. } |
943+
TerminatorKind::FalseUnwind { ref mut unwind, .. } => {
920944
Some(unwind)
921945
}
922946
}
@@ -1045,7 +1069,8 @@ impl<'tcx> TerminatorKind<'tcx> {
10451069

10461070
write!(fmt, ")")
10471071
},
1048-
FalseEdges { .. } => write!(fmt, "falseEdges")
1072+
FalseEdges { .. } => write!(fmt, "falseEdges"),
1073+
FalseUnwind { .. } => write!(fmt, "falseUnwind"),
10491074
}
10501075
}
10511076

@@ -1087,6 +1112,8 @@ impl<'tcx> TerminatorKind<'tcx> {
10871112
l.resize(imaginary_targets.len() + 1, "imaginary".into());
10881113
l
10891114
}
1115+
FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
1116+
FalseUnwind { unwind: None, .. } => vec!["real".into()],
10901117
}
10911118
}
10921119
}
@@ -2189,7 +2216,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
21892216
Return => Return,
21902217
Unreachable => Unreachable,
21912218
FalseEdges { real_target, ref imaginary_targets } =>
2192-
FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }
2219+
FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() },
2220+
FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
21932221
};
21942222
Terminator {
21952223
source_info: self.source_info,
@@ -2231,7 +2259,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
22312259
Return |
22322260
GeneratorDrop |
22332261
Unreachable |
2234-
FalseEdges { .. } => false
2262+
FalseEdges { .. } |
2263+
FalseUnwind { .. } => false
22352264
}
22362265
}
22372266
}

src/librustc/mir/visit.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -495,15 +495,21 @@ macro_rules! make_mir_visitor {
495495
self.visit_operand(value, source_location);
496496
self.visit_branch(block, resume);
497497
drop.map(|t| self.visit_branch(block, t));
498-
499498
}
500499

501-
TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
500+
TerminatorKind::FalseEdges { real_target, ref imaginary_targets} => {
502501
self.visit_branch(block, real_target);
503502
for target in imaginary_targets {
504503
self.visit_branch(block, *target);
505504
}
506505
}
506+
507+
TerminatorKind::FalseUnwind { real_target, unwind } => {
508+
self.visit_branch(block, real_target);
509+
if let Some(unwind) = unwind {
510+
self.visit_branch(block, unwind);
511+
}
512+
}
507513
}
508514
}
509515

src/librustc_mir/borrow_check/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
576576
TerminatorKind::Goto { target: _ }
577577
| TerminatorKind::Abort
578578
| TerminatorKind::Unreachable
579-
| TerminatorKind::FalseEdges { .. } => {
579+
| TerminatorKind::FalseEdges { real_target: _, imaginary_targets: _ }
580+
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
580581
// no data used, thus irrelevant to borrowck
581582
}
582583
}

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
796796
| TerminatorKind::GeneratorDrop
797797
| TerminatorKind::Unreachable
798798
| TerminatorKind::Drop { .. }
799-
| TerminatorKind::FalseEdges { .. } => {
799+
| TerminatorKind::FalseEdges { .. }
800+
| TerminatorKind::FalseUnwind { .. } => {
800801
// no checks needed for these
801802
}
802803

@@ -1152,6 +1153,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11521153
self.assert_iscleanup(mir, block_data, *target, is_cleanup);
11531154
}
11541155
}
1156+
TerminatorKind::FalseUnwind {
1157+
real_target,
1158+
unwind
1159+
} => {
1160+
self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
1161+
if let Some(unwind) = unwind {
1162+
if is_cleanup {
1163+
span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind");
1164+
}
1165+
self.assert_iscleanup(mir, block_data, unwind, true);
1166+
}
1167+
}
11551168
}
11561169
}
11571170

src/librustc_mir/build/matches/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
728728
TerminatorKind::FalseEdges {
729729
real_target: block,
730730
imaginary_targets:
731-
vec![candidate.next_candidate_pre_binding_block]});
731+
vec![candidate.next_candidate_pre_binding_block],
732+
});
732733

733734
self.bind_matched_candidate(block, candidate.bindings);
734735

@@ -749,7 +750,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
749750
TerminatorKind::FalseEdges {
750751
real_target: otherwise,
751752
imaginary_targets:
752-
vec![candidate.next_candidate_pre_binding_block] });
753+
vec![candidate.next_candidate_pre_binding_block],
754+
});
753755
Some(otherwise)
754756
} else {
755757
self.cfg.terminate(block, candidate_source_info,

src/librustc_mir/dataflow/impls/borrows.rs

+1
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
517517
mir::TerminatorKind::Yield {..} |
518518
mir::TerminatorKind::Goto {..} |
519519
mir::TerminatorKind::FalseEdges {..} |
520+
mir::TerminatorKind::FalseUnwind {..} |
520521
mir::TerminatorKind::Unreachable => {}
521522
}
522523
}

src/librustc_mir/dataflow/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,14 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
864864
self.propagate_bits_into_entry_set_for(in_out, changed, target);
865865
}
866866
}
867+
mir::TerminatorKind::FalseUnwind { ref real_target, unwind } => {
868+
self.propagate_bits_into_entry_set_for(in_out, changed, real_target);
869+
if let Some(ref unwind) = unwind {
870+
if !self.dead_unwinds.contains(&bb) {
871+
self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
872+
}
873+
}
874+
}
867875
}
868876
}
869877

src/librustc_mir/dataflow/move_paths/builder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
346346
TerminatorKind::Abort |
347347
TerminatorKind::GeneratorDrop |
348348
TerminatorKind::FalseEdges { .. } |
349+
TerminatorKind::FalseUnwind { .. } |
349350
TerminatorKind::Unreachable => { }
350351

351352
TerminatorKind::Return => {

src/librustc_mir/interpret/terminator/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
165165
Resume => unimplemented!(),
166166
Abort => unimplemented!(),
167167
FalseEdges { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
168+
FalseUnwind { .. } => bug!("should have been eliminated by `simplify_branches` mir pass"),
168169
Unreachable => return err!(Unreachable),
169170
}
170171

src/librustc_mir/monomorphize/collector.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
636636
mir::TerminatorKind::Assert { .. } => {}
637637
mir::TerminatorKind::GeneratorDrop |
638638
mir::TerminatorKind::Yield { .. } |
639-
mir::TerminatorKind::FalseEdges { .. } => bug!(),
639+
mir::TerminatorKind::FalseEdges { .. } |
640+
mir::TerminatorKind::FalseUnwind { .. } => bug!(),
640641
}
641642

642643
self.super_terminator_kind(block, kind, location);

src/librustc_mir/transform/check_unsafety.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
7676
TerminatorKind::Abort |
7777
TerminatorKind::Return |
7878
TerminatorKind::Unreachable |
79-
TerminatorKind::FalseEdges { .. } => {
79+
TerminatorKind::FalseEdges { .. } |
80+
TerminatorKind::FalseUnwind { .. } => {
8081
// safe (at least as emitted during MIR construction)
8182
}
8283

src/librustc_mir/transform/inline.rs

+3
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
813813
*target = self.update_target(*target);
814814
}
815815
}
816+
TerminatorKind::FalseUnwind { real_target: _ , unwind: _ } =>
817+
// see the ordering of passes in the optimized_mir query.
818+
bug!("False unwinds should have been removed before inlining")
816819
}
817820
}
818821

src/librustc_mir/transform/qualify_consts.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
327327
TerminatorKind::GeneratorDrop |
328328
TerminatorKind::Yield { .. } |
329329
TerminatorKind::Unreachable |
330-
TerminatorKind::FalseEdges { .. } => None,
330+
TerminatorKind::FalseEdges { .. } |
331+
TerminatorKind::FalseUnwind { .. } => None,
331332

332333
TerminatorKind::Return => {
333334
// Check for unused values. This usually means

src/librustc_mir/transform/remove_noop_landing_pads.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ impl RemoveNoopLandingPads {
7575
TerminatorKind::Goto { .. } |
7676
TerminatorKind::Resume |
7777
TerminatorKind::SwitchInt { .. } |
78-
TerminatorKind::FalseEdges { .. } => {
78+
TerminatorKind::FalseEdges { .. } |
79+
TerminatorKind::FalseUnwind { .. } => {
7980
terminator.successors().iter().all(|succ| {
8081
nop_landing_pads.contains(succ.index())
8182
})

src/librustc_mir/transform/simplify_branches.rs

+3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ impl MirPass for SimplifyBranches {
6464
TerminatorKind::FalseEdges { real_target, .. } => {
6565
TerminatorKind::Goto { target: real_target }
6666
},
67+
TerminatorKind::FalseUnwind { real_target, .. } => {
68+
TerminatorKind::Goto { target: real_target }
69+
},
6770
_ => continue
6871
};
6972
}

src/librustc_passes/mir_stats.rs

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
123123
TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
124124
TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
125125
TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
126+
TerminatorKind::FalseUnwind { .. } => "TerminatorKind::FalseUnwind",
126127
}, kind);
127128
self.super_terminator_kind(block, kind, location);
128129
}

src/librustc_trans/mir/analyze.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock
242242
TerminatorKind::Unreachable |
243243
TerminatorKind::SwitchInt { .. } |
244244
TerminatorKind::Yield { .. } |
245-
TerminatorKind::FalseEdges { .. } => {
245+
TerminatorKind::FalseEdges { .. } |
246+
TerminatorKind::FalseUnwind { .. } => {
246247
/* nothing to do */
247248
}
248249
TerminatorKind::Call { cleanup: unwind, .. } |

src/librustc_trans/mir/block.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,9 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
608608
cleanup);
609609
}
610610
mir::TerminatorKind::GeneratorDrop |
611-
mir::TerminatorKind::Yield { .. } |
612-
mir::TerminatorKind::FalseEdges { .. } => bug!("generator ops in trans"),
611+
mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"),
612+
mir::TerminatorKind::FalseEdges { .. } |
613+
mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in trans"),
613614
}
614615
}
615616

0 commit comments

Comments
 (0)