Skip to content

Commit 1ae7ae0

Browse files
committed
fix translation of terminators in MSVC cleanup blocks
MSVC requires unwinding code to be split to a tree of *funclets*, where each funclet can only branch to itself or to to its parent. Luckily, the code we generates matches this pattern. Recover that structure in an analyze pass and translate according to that.
1 parent 506086e commit 1ae7ae0

File tree

7 files changed

+347
-105
lines changed

7 files changed

+347
-105
lines changed

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -998,9 +998,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
998998
continue
999999
}
10001000
TerminatorKind::DropAndReplace { .. } => {
1001-
// this contains the consume of the source and
1001+
// this contains the move of the source and
10021002
// the initialization of the destination. We
1003-
// only want the latter
1003+
// only want the former - the latter is handled
1004+
// by the elaboration code and must be done
1005+
// *after* the destination is dropped.
10041006
assert!(self.patch.is_patched(bb));
10051007
allow_initializations = false;
10061008
}

src/librustc_trans/common.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,15 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
577577
self.lpad.get()
578578
}
579579

580+
pub fn set_lpad_ref(&self, lpad: Option<&'blk LandingPad>) {
581+
// FIXME: use an IVar?
582+
self.lpad.set(lpad);
583+
}
584+
585+
pub fn set_lpad(&self, lpad: Option<LandingPad>) {
586+
self.set_lpad_ref(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
587+
}
588+
580589
pub fn mir(&self) -> CachedMir<'blk, 'tcx> {
581590
self.fcx.mir()
582591
}
@@ -716,7 +725,16 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
716725
}
717726

718727
pub fn set_lpad(&self, lpad: Option<LandingPad>) {
719-
self.bcx.lpad.set(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
728+
self.bcx.set_lpad(lpad)
729+
}
730+
731+
pub fn set_lpad_ref(&self, lpad: Option<&'blk LandingPad>) {
732+
// FIXME: use an IVar?
733+
self.bcx.set_lpad_ref(lpad);
734+
}
735+
736+
pub fn lpad(&self) -> Option<&'blk LandingPad> {
737+
self.bcx.lpad()
720738
}
721739
}
722740

@@ -761,6 +779,10 @@ impl LandingPad {
761779
pub fn bundle(&self) -> Option<&OperandBundleDef> {
762780
self.operand.as_ref()
763781
}
782+
783+
pub fn cleanuppad(&self) -> Option<ValueRef> {
784+
self.cleanuppad
785+
}
764786
}
765787

766788
impl Clone for LandingPad {

src/librustc_trans/mir/analyze.rs

+103
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
1414
use rustc_data_structures::bitvec::BitVector;
1515
use rustc::mir::repr as mir;
16+
use rustc::mir::repr::TerminatorKind;
1617
use rustc::mir::visit::{Visitor, LvalueContext};
18+
use rustc_mir::traversal;
1719
use common::{self, Block, BlockAndBuilder};
1820
use super::rvalue;
1921

@@ -134,3 +136,104 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
134136
self.super_lvalue(lvalue, context);
135137
}
136138
}
139+
140+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
141+
pub enum CleanupKind {
142+
NotCleanup,
143+
Funclet,
144+
Internal { funclet: mir::BasicBlock }
145+
}
146+
147+
pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>,
148+
mir: &mir::Mir<'tcx>)
149+
-> Vec<CleanupKind>
150+
{
151+
fn discover_masters<'tcx>(result: &mut [CleanupKind], mir: &mir::Mir<'tcx>) {
152+
for bb in mir.all_basic_blocks() {
153+
let data = mir.basic_block_data(bb);
154+
match data.terminator().kind {
155+
TerminatorKind::Goto { .. } |
156+
TerminatorKind::Resume |
157+
TerminatorKind::Return |
158+
TerminatorKind::If { .. } |
159+
TerminatorKind::Switch { .. } |
160+
TerminatorKind::SwitchInt { .. } => {
161+
/* nothing to do */
162+
}
163+
TerminatorKind::Call { cleanup: unwind, .. } |
164+
TerminatorKind::DropAndReplace { unwind, .. } |
165+
TerminatorKind::Drop { unwind, .. } => {
166+
if let Some(unwind) = unwind {
167+
debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
168+
bb, data, unwind);
169+
result[unwind.index()] = CleanupKind::Funclet;
170+
}
171+
}
172+
}
173+
}
174+
}
175+
176+
fn propagate<'tcx>(result: &mut [CleanupKind], mir: &mir::Mir<'tcx>) {
177+
let mut funclet_succs : Vec<_> =
178+
mir.all_basic_blocks().iter().map(|_| None).collect();
179+
180+
let mut set_successor = |funclet: mir::BasicBlock, succ| {
181+
match funclet_succs[funclet.index()] {
182+
ref mut s @ None => {
183+
debug!("set_successor: updating successor of {:?} to {:?}",
184+
funclet, succ);
185+
*s = Some(succ);
186+
},
187+
Some(s) => if s != succ {
188+
span_bug!(mir.span, "funclet {:?} has 2 parents - {:?} and {:?}",
189+
funclet, s, succ);
190+
}
191+
}
192+
};
193+
194+
for (bb, data) in traversal::reverse_postorder(mir) {
195+
let funclet = match result[bb.index()] {
196+
CleanupKind::NotCleanup => continue,
197+
CleanupKind::Funclet => bb,
198+
CleanupKind::Internal { funclet } => funclet,
199+
};
200+
201+
debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
202+
bb, data, result[bb.index()], funclet);
203+
204+
for &succ in data.terminator().successors().iter() {
205+
let kind = result[succ.index()];
206+
debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}",
207+
funclet, succ, kind);
208+
match kind {
209+
CleanupKind::NotCleanup => {
210+
result[succ.index()] = CleanupKind::Internal { funclet: funclet };
211+
}
212+
CleanupKind::Funclet => {
213+
set_successor(funclet, succ);
214+
}
215+
CleanupKind::Internal { funclet: succ_funclet } => {
216+
if funclet != succ_funclet {
217+
// `succ` has 2 different funclet going into it, so it must
218+
// be a funclet by itself.
219+
220+
debug!("promoting {:?} to a funclet and updating {:?}", succ,
221+
succ_funclet);
222+
result[succ.index()] = CleanupKind::Funclet;
223+
set_successor(succ_funclet, succ);
224+
set_successor(funclet, succ);
225+
}
226+
}
227+
}
228+
}
229+
}
230+
}
231+
232+
let mut result : Vec<_> =
233+
mir.all_basic_blocks().iter().map(|_| CleanupKind::NotCleanup).collect();
234+
235+
discover_masters(&mut result, mir);
236+
propagate(&mut result, mir);
237+
debug!("cleanup_kinds: result={:?}", result);
238+
result
239+
}

0 commit comments

Comments
 (0)