diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ffc54bbed35..53f2729c38e 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1317,26 +1317,38 @@ pub fn cleanup_and_leave(bcx: block, match cur.kind { block_scope(inf) if !inf.empty_cleanups() => { - let (sub_cx, inf_cleanups) = { + let (sub_cx, dest, inf_cleanups) = { let inf = &mut *inf; // FIXME(#5074) workaround stage0 + let mut skip = 0; + let mut dest = None; { - let r = vec::find((*inf).cleanup_paths, |cp| cp.target == leave); + let r = vec::rfind((*inf).cleanup_paths, |cp| cp.target == leave); for r.iter().advance |cp| { - Br(bcx, cp.dest); - return; + if cp.size == inf.cleanups.len() { + Br(bcx, cp.dest); + return; + } + + skip = cp.size; + dest = Some(cp.dest); } } let sub_cx = sub_block(bcx, "cleanup"); Br(bcx, sub_cx.llbb); inf.cleanup_paths.push(cleanup_path { target: leave, + size: inf.cleanups.len(), dest: sub_cx.llbb }); - (sub_cx, copy inf.cleanups) + (sub_cx, dest, inf.cleanups.tailn(skip).to_owned()) }; bcx = trans_block_cleanups_(sub_cx, inf_cleanups, is_lpad); + for dest.iter().advance |&dest| { + Br(bcx, dest); + return; + } } _ => () } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f5919ca2586..ff98e5a177f 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -325,11 +325,17 @@ pub enum cleanup { // target: none means the path ends in an resume instruction pub struct cleanup_path { target: Option, + size: uint, dest: BasicBlockRef } -pub fn scope_clean_changed(scope_info: &mut scope_info) { - if scope_info.cleanup_paths.len() > 0u { scope_info.cleanup_paths = ~[]; } +pub fn shrink_scope_clean(scope_info: &mut scope_info, size: uint) { + scope_info.landing_pad = None; + scope_info.cleanup_paths = scope_info.cleanup_paths.iter() + .take_while(|&cu| cu.size <= size).transform(|&x|x).collect(); +} + +pub fn grow_scope_clean(scope_info: &mut scope_info) { scope_info.landing_pad = None; } @@ -374,7 +380,7 @@ pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) { scope_info.cleanups.push( clean(|a| glue::drop_ty_root(a, root, rooted, t), cleanup_type)); - scope_clean_changed(scope_info); + grow_scope_clean(scope_info); } } @@ -388,7 +394,7 @@ pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { scope_info.cleanups.push( clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty), cleanup_type)); - scope_clean_changed(scope_info); + grow_scope_clean(scope_info); } } pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { @@ -402,7 +408,7 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { scope_info.cleanups.push( clean_temp(val, |a| glue::drop_ty_root(a, root, rooted, t), cleanup_type)); - scope_clean_changed(scope_info); + grow_scope_clean(scope_info); } } pub fn add_clean_return_to_mut(bcx: block, @@ -434,7 +440,7 @@ pub fn add_clean_return_to_mut(bcx: block, filename_val, line_val), normal_exit_only)); - scope_clean_changed(scope_info); + grow_scope_clean(scope_info); } } pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { @@ -451,7 +457,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { do in_scope_cx(cx) |scope_info| { scope_info.cleanups.push(clean_temp(ptr, free_fn, normal_exit_and_unwind)); - scope_clean_changed(scope_info); + grow_scope_clean(scope_info); } } @@ -474,7 +480,7 @@ pub fn revoke_clean(cx: block, val: ValueRef) { vec::slice(scope_info.cleanups, *i + 1u, scope_info.cleanups.len())); - scope_clean_changed(scope_info); + shrink_scope_clean(scope_info, *i); } } }