Skip to content

Commit ecf4d0e

Browse files
committed
Add Resume Terminator which corresponds to resume
Diverge should eventually go away
1 parent 6f18b55 commit ecf4d0e

File tree

6 files changed

+70
-45
lines changed

6 files changed

+70
-45
lines changed

src/librustc/mir/repr.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ pub enum Terminator<'tcx> {
251251
/// well-known diverging block actually diverges.
252252
Diverge,
253253

254+
/// Indicates that the landing pad is finished and unwinding should
255+
/// continue. Emitted by build::scope::diverge_cleanup.
256+
Resume,
257+
254258
/// Indicates a normal return. The ReturnPointer lvalue should
255259
/// have been filled in by now. This should only occur in the
256260
/// `END_BLOCK`.
@@ -288,6 +292,14 @@ pub enum CallTargets {
288292
}
289293

290294
impl CallTargets {
295+
pub fn new(ret: BasicBlock, cleanup: Option<BasicBlock>) -> CallTargets {
296+
if let Some(c) = cleanup {
297+
CallTargets::WithCleanup((ret, c))
298+
} else {
299+
CallTargets::Return(ret)
300+
}
301+
}
302+
291303
pub fn as_slice(&self) -> &[BasicBlock] {
292304
match *self {
293305
CallTargets::Return(ref b) => slice::ref_slice(b),
@@ -313,6 +325,7 @@ impl<'tcx> Terminator<'tcx> {
313325
Switch { targets: ref b, .. } => b,
314326
SwitchInt { targets: ref b, .. } => b,
315327
Diverge => &[],
328+
Resume => &[],
316329
Return => &[],
317330
Call { targets: ref b, .. } => b.as_slice(),
318331
DivergingCall { cleanup: ref b, .. } => if let Some(b) = b.as_ref() {
@@ -332,6 +345,7 @@ impl<'tcx> Terminator<'tcx> {
332345
Switch { targets: ref mut b, .. } => b,
333346
SwitchInt { targets: ref mut b, .. } => b,
334347
Diverge => &mut [],
348+
Resume => &mut [],
335349
Return => &mut [],
336350
Call { targets: ref mut b, .. } => b.as_mut_slice(),
337351
DivergingCall { cleanup: ref mut b, .. } => if let Some(b) = b.as_mut() {
@@ -393,6 +407,7 @@ impl<'tcx> Terminator<'tcx> {
393407
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
394408
Diverge => write!(fmt, "diverge"),
395409
Return => write!(fmt, "return"),
410+
Resume => write!(fmt, "resume"),
396411
Call { .. } => {
397412
// the author didn’t bother rebasing this
398413
unimplemented!()
@@ -408,7 +423,7 @@ impl<'tcx> Terminator<'tcx> {
408423
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
409424
use self::Terminator::*;
410425
match *self {
411-
Diverge | Return => vec![],
426+
Diverge | Return | Resume => vec![],
412427
Goto { .. } | Panic { .. } => vec!["".into_cow()],
413428
If { .. } => vec!["true".into_cow(), "false".into_cow()],
414429
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],

src/librustc/mir/visit.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ pub trait Visitor<'tcx> {
134134
}
135135

136136
Terminator::Diverge |
137+
Terminator::Resume |
137138
Terminator::Return => {
138139
}
139140

@@ -431,6 +432,7 @@ pub trait MutVisitor<'tcx> {
431432
}
432433

433434
Terminator::Diverge |
435+
Terminator::Resume |
434436
Terminator::Return => {
435437
}
436438

src/librustc_mir/build/expr/into.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
225225
let success = this.cfg.start_new_block();
226226
let cleanup = this.diverge_cleanup();
227227
let term = if diverges {
228-
Terminator::DivergingCall { func: fun, args: args, cleanup: Some(cleanup) }
228+
Terminator::DivergingCall { func: fun, args: args, cleanup: cleanup }
229229
} else {
230230
Terminator::Call {
231231
func: fun,
232232
args: args,
233233
destination: destination.clone(),
234-
targets: CallTargets::WithCleanup((success, cleanup))
234+
targets: CallTargets::new(success, cleanup)
235235
}
236236
};
237237
this.cfg.terminate(block, term);

src/librustc_mir/build/scope.rs

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ should go to.
8686
8787
*/
8888

89-
use build::{BlockAnd, BlockAndExtension, Builder, CFG};
89+
use build::{BlockAnd, BlockAndExtension, Builder};
9090
use rustc::middle::region::CodeExtent;
9191
use rustc::middle::ty::Ty;
9292
use rustc::mir::repr::*;
@@ -227,16 +227,44 @@ impl<'a,'tcx> Builder<'a,'tcx> {
227227
self.cfg.terminate(block, Terminator::Goto { target: target });
228228
}
229229

230-
/// Creates a path that performs all required cleanup for
231-
/// unwinding. This path terminates in DIVERGE. Returns the start
232-
/// of the path. See module comment for more details.
233-
pub fn diverge_cleanup(&mut self) -> BasicBlock {
234-
diverge_cleanup_helper(&mut self.cfg, &mut self.scopes)
230+
/// Creates a path that performs all required cleanup for unwinding.
231+
///
232+
/// This path terminates in Resume. Returns the start of the path.
233+
/// See module comment for more details. None indicates there’s no
234+
/// cleanup to do at this point.
235+
pub fn diverge_cleanup(&mut self) -> Option<BasicBlock> {
236+
if self.scopes.is_empty() {
237+
return None;
238+
}
239+
240+
let mut terminator = Terminator::Resume;
241+
// Given an array of scopes, we generate these from the outermost scope to the innermost
242+
// one. Thus for array [S0, S1, S2] with corresponding cleanup blocks [B0, B1, B2], we will
243+
// generate B0 <- B1 <- B2 in left-to-right order. The outermost scope (B0) will always
244+
// terminate with a Resume terminator.
245+
for scope in self.scopes.iter_mut().filter(|s| !s.drops.is_empty()) {
246+
if let Some(b) = scope.cached_block {
247+
terminator = Terminator::Goto { target: b };
248+
continue;
249+
} else {
250+
let new_block = self.cfg.start_new_block();
251+
self.cfg.terminate(new_block, terminator);
252+
terminator = Terminator::Goto { target: new_block };
253+
for &(kind, span, ref lvalue) in scope.drops.iter().rev() {
254+
self.cfg.push_drop(new_block, span, kind, lvalue);
255+
}
256+
scope.cached_block = Some(new_block);
257+
}
258+
}
259+
// Return the innermost cached block, most likely the one we just generated.
260+
// Note that if there are no cleanups in scope we return None.
261+
self.scopes.iter().rev().flat_map(|b| b.cached_block).next()
235262
}
236263

237264
/// Create diverge cleanup and branch to it from `block`.
238265
pub fn panic(&mut self, block: BasicBlock) {
239-
let cleanup = self.diverge_cleanup();
266+
// FIXME: panic terminator should also have conditional cleanup?
267+
let cleanup = self.diverge_cleanup().unwrap_or(DIVERGE_BLOCK);
240268
self.cfg.terminate(block, Terminator::Panic { target: cleanup });
241269
}
242270

@@ -249,14 +277,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
249277
lvalue: &Lvalue<'tcx>,
250278
lvalue_ty: Ty<'tcx>) {
251279
if self.hir.needs_drop(lvalue_ty) {
252-
match self.scopes.iter_mut().rev().find(|s| s.extent == extent) {
253-
Some(scope) => {
280+
for scope in self.scopes.iter_mut().rev() {
281+
// We must invalidate all the cached_blocks leading up to the scope we’re looking
282+
// for, because otherwise some/most of the blocks in the chain might become
283+
// incorrect (i.e. they still are pointing at old cached_block).
284+
scope.cached_block = None;
285+
if scope.extent == extent {
254286
scope.drops.push((kind, span, lvalue.clone()));
255-
scope.cached_block = None;
287+
return;
256288
}
257-
None => self.hir.span_bug(span, &format!("extent {:?} not in scope to drop {:?}",
258-
extent, lvalue)),
259289
}
290+
self.hir.span_bug(span,
291+
&format!("extent {:?} not in scope to drop {:?}", extent, lvalue));
260292
}
261293
}
262294

@@ -268,28 +300,3 @@ impl<'a,'tcx> Builder<'a,'tcx> {
268300
self.scopes.first().map(|scope| scope.extent).unwrap()
269301
}
270302
}
271-
272-
fn diverge_cleanup_helper<'tcx>(cfg: &mut CFG<'tcx>, scopes: &mut [Scope<'tcx>]) -> BasicBlock {
273-
let len = scopes.len();
274-
275-
if len == 0 {
276-
return DIVERGE_BLOCK;
277-
}
278-
279-
let (remaining, scope) = scopes.split_at_mut(len - 1);
280-
let scope = &mut scope[0];
281-
282-
if let Some(b) = scope.cached_block {
283-
return b;
284-
}
285-
286-
let block = cfg.start_new_block();
287-
for &(kind, span, ref lvalue) in &scope.drops {
288-
cfg.push_drop(block, span, kind, lvalue);
289-
}
290-
scope.cached_block = Some(block);
291-
292-
let remaining_cleanup_block = diverge_cleanup_helper(cfg, remaining);
293-
cfg.terminate(block, Terminator::Goto { target: remaining_cleanup_block });
294-
block
295-
}

src/librustc_mir/transform/erase_regions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
8080
match *terminator {
8181
Terminator::Goto { .. } |
8282
Terminator::Diverge |
83+
Terminator::Resume |
8384
Terminator::Return |
8485
Terminator::Panic { .. } => {
8586
/* nothing to do */

src/librustc_trans/trans/mir/block.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
8787
}
8888

8989
mir::Terminator::Diverge => {
90+
build::Unreachable(bcx);
91+
}
92+
93+
mir::Terminator::Resume => {
9094
if let Some(llpersonalityslot) = self.llpersonalityslot {
9195
let lp = build::Load(bcx, llpersonalityslot);
9296
// FIXME(lifetime) base::call_lifetime_end(bcx, self.personality);
9397
build::Resume(bcx, lp);
9498
} else {
95-
// This fn never encountered anything fallible, so
96-
// a Diverge cannot actually happen. Note that we
97-
// do a total hack to ensure that we visit the
98-
// DIVERGE block last.
99-
build::Unreachable(bcx);
99+
panic!("resume terminator without personality slot")
100100
}
101101
}
102102

0 commit comments

Comments
 (0)