diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d6105cc1dded..d3ff63a959bd 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -863,10 +863,10 @@ pub fn need_invoke(bcx: block) -> bool { // Walk the scopes to look for cleanups let mut cur = bcx; + let mut cur_scope = cur.scope; loop { - match cur.kind { - block_scope(inf) => { - let inf = &mut *inf; // FIXME(#5074) workaround old borrowck + cur_scope = match cur_scope { + Some(inf) => { for inf.cleanups.iter().advance |cleanup| { match *cleanup { clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { @@ -876,12 +876,15 @@ pub fn need_invoke(bcx: block) -> bool { } } } + inf.parent + } + None => { + cur = match cur.parent { + Some(next) => next, + None => return false + }; + cur.scope } - _ => () - } - cur = match cur.parent { - Some(next) => next, - None => return false } } } @@ -899,23 +902,21 @@ pub fn have_cached_lpad(bcx: block) -> bool { pub fn in_lpad_scope_cx(bcx: block, f: &fn(si: &mut scope_info)) { let mut bcx = bcx; + let mut cur_scope = bcx.scope; loop { - { - match bcx.kind { - block_scope(inf) => { - let len = { // FIXME(#5074) workaround old borrowck - let inf = &mut *inf; - inf.cleanups.len() - }; - if len > 0u || bcx.parent.is_none() { - f(inf); - return; - } + cur_scope = match cur_scope { + Some(inf) => { + if !inf.empty_cleanups() || (inf.parent.is_none() && bcx.parent.is_none()) { + f(inf); + return; } - _ => () + inf.parent + } + None => { + bcx = block_parent(bcx); + bcx.scope } } - bcx = block_parent(bcx); } } @@ -972,27 +973,31 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { let mut bcx_sid = bcx; + let mut cur_scope = bcx_sid.scope; loop { - bcx_sid = match bcx_sid.node_info { - Some(NodeInfo { id, _ }) if id == scope_id => { - return bcx_sid - } - - // FIXME(#6268, #6248) hacky cleanup for nested method calls - Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { - return bcx_sid - } - - _ => { - match bcx_sid.parent { - None => bcx.tcx().sess.bug( - fmt!("no enclosing scope with id %d", scope_id)), - Some(bcx_par) => bcx_par + cur_scope = match cur_scope { + Some(inf) => { + match inf.node_info { + Some(NodeInfo { id, _ }) if id == scope_id => { + return bcx_sid } + // FIXME(#6268, #6248) hacky cleanup for nested method calls + Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { + return bcx_sid + } + _ => inf.parent } } + None => { + bcx_sid = match bcx_sid.parent { + None => bcx.tcx().sess.bug(fmt!("no enclosing scope with id %d", scope_id)), + Some(bcx_par) => bcx_par + }; + bcx_sid.scope + } } } +} pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { @@ -1145,7 +1150,7 @@ pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { // You probably don't want to use this one. See the // next three functions instead. -pub fn new_block(cx: fn_ctxt, parent: Option, kind: block_kind, +pub fn new_block(cx: fn_ctxt, parent: Option, scope: Option<@mut scope_info>, is_lpad: bool, name: &str, opt_node_info: Option) -> block { @@ -1155,10 +1160,10 @@ pub fn new_block(cx: fn_ctxt, parent: Option, kind: block_kind, }; let bcx = mk_block(llbb, parent, - kind, is_lpad, opt_node_info, cx); + bcx.scope = scope; for parent.iter().advance |cx| { if cx.unreachable { Unreachable(bcx); @@ -1169,27 +1174,30 @@ pub fn new_block(cx: fn_ctxt, parent: Option, kind: block_kind, } } -pub fn simple_block_scope() -> block_kind { - block_scope(@mut scope_info { +pub fn simple_block_scope(parent: Option<@mut scope_info>, + node_info: Option) -> @mut scope_info { + @mut scope_info { + parent: parent, loop_break: None, loop_label: None, cleanups: ~[], cleanup_paths: ~[], - landing_pad: None - }) + landing_pad: None, + node_info: node_info, + } } // Use this when you're at the top block of a function or the like. pub fn top_scope_block(fcx: fn_ctxt, opt_node_info: Option) -> block { - return new_block(fcx, None, simple_block_scope(), false, + return new_block(fcx, None, Some(simple_block_scope(None, opt_node_info)), false, "function top level", opt_node_info); } pub fn scope_block(bcx: block, opt_node_info: Option, n: &str) -> block { - return new_block(bcx.fcx, Some(bcx), simple_block_scope(), bcx.is_lpad, + return new_block(bcx.fcx, Some(bcx), Some(simple_block_scope(None, opt_node_info)), bcx.is_lpad, n, opt_node_info); } @@ -1198,27 +1206,29 @@ pub fn loop_scope_block(bcx: block, loop_label: Option, n: &str, opt_node_info: Option) -> block { - return new_block(bcx.fcx, Some(bcx), block_scope(@mut scope_info { + return new_block(bcx.fcx, Some(bcx), Some(@mut scope_info { + parent: None, loop_break: Some(loop_break), loop_label: loop_label, cleanups: ~[], cleanup_paths: ~[], - landing_pad: None + landing_pad: None, + node_info: opt_node_info, }), bcx.is_lpad, n, opt_node_info); } // Use this when creating a block for the inside of a landing pad. pub fn lpad_block(bcx: block, n: &str) -> block { - new_block(bcx.fcx, Some(bcx), block_non_scope, true, n, None) + new_block(bcx.fcx, Some(bcx), None, true, n, None) } // Use this when you're making a general CFG BB within a scope. pub fn sub_block(bcx: block, n: &str) -> block { - new_block(bcx.fcx, Some(bcx), block_non_scope, bcx.is_lpad, n, None) + new_block(bcx.fcx, Some(bcx), None, bcx.is_lpad, n, None) } pub fn raw_block(fcx: fn_ctxt, is_lpad: bool, llbb: BasicBlockRef) -> block { - mk_block(llbb, None, block_non_scope, is_lpad, None, fcx) + mk_block(llbb, None, is_lpad, None, fcx) } @@ -1277,42 +1287,47 @@ pub fn cleanup_and_leave(bcx: block, (fmt!("cleanup_and_leave(%s)", cur.to_str())).to_managed()); } - match cur.kind { - block_scope(inf) if !inf.empty_cleanups() => { - let (sub_cx, dest, inf_cleanups) = { - let inf = &mut *inf; - let mut skip = 0; - let mut dest = None; - { - let r = (*inf).cleanup_paths.rev_iter().find_(|cp| cp.target == leave); - for r.iter().advance |cp| { - if cp.size == inf.cleanups.len() { - Br(bcx, cp.dest); - return; - } + let mut cur_scope = cur.scope; + loop { + cur_scope = match cur_scope { + Some (inf) if !inf.empty_cleanups() => { + let (sub_cx, dest, inf_cleanups) = { + let inf = &mut *inf; + let mut skip = 0; + let mut dest = None; + { + let r = (*inf).cleanup_paths.rev_iter().find_(|cp| cp.target == leave); + for r.iter().advance |cp| { + if cp.size == inf.cleanups.len() { + Br(bcx, cp.dest); + return; + } - skip = cp.size; - dest = Some(cp.dest); + 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, 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; } - 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, 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; + inf.parent } + Some(inf) => inf.parent, + None => break } - _ => () } match upto { @@ -1353,9 +1368,12 @@ pub fn with_scope(bcx: block, bcx.to_str(), opt_node_info, name); let _indenter = indenter(); - let scope_cx = scope_block(bcx, opt_node_info, name); - Br(bcx, scope_cx.llbb); - leave_block(f(scope_cx), scope_cx) + let scope = simple_block_scope(bcx.scope, opt_node_info); + bcx.scope = Some(scope); + let ret = f(bcx); + let ret = trans_block_cleanups_(ret, /*bad*/copy scope.cleanups, false); + bcx.scope = scope.parent; + ret } pub fn with_scope_result(bcx: block, @@ -1363,10 +1381,14 @@ pub fn with_scope_result(bcx: block, name: &str, f: &fn(block) -> Result) -> Result { let _icx = push_ctxt("with_scope_result"); - let scope_cx = scope_block(bcx, opt_node_info, name); - Br(bcx, scope_cx.llbb); - let Result {bcx, val} = f(scope_cx); - rslt(leave_block(bcx, scope_cx), val) + + let scope = simple_block_scope(bcx.scope, opt_node_info); + bcx.scope = Some(scope); + let Result { bcx: out_bcx, val } = f(bcx); + let out_bcx = trans_block_cleanups_(out_bcx, /*bad*/copy scope.cleanups, false); + bcx.scope = scope.parent; + + rslt(out_bcx, val) } pub fn with_scope_datumblock(bcx: block, opt_node_info: Option, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 865fb26b9455..11859947e1e9 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -321,7 +321,7 @@ pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) { debug!("add_clean(%s, %s, %s)", bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx())); let cleanup_type = cleanup_type(bcx.tcx(), t); - do in_scope_cx(bcx) |scope_info| { + do in_scope_cx(bcx, None) |scope_info| { scope_info.cleanups.push(clean(|a| glue::drop_ty(a, val, t), cleanup_type)); grow_scope_clean(scope_info); } @@ -333,25 +333,36 @@ pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { cx.to_str(), cx.val_to_str(val), ty.repr(cx.tcx())); let cleanup_type = cleanup_type(cx.tcx(), ty); - do in_scope_cx(cx) |scope_info| { + do in_scope_cx(cx, None) |scope_info| { scope_info.cleanups.push( clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty), cleanup_type)); grow_scope_clean(scope_info); } } + pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { + add_clean_temp_mem_in_scope_(bcx, None, val, t); +} + +pub fn add_clean_temp_mem_in_scope(bcx: block, scope_id: ast::node_id, val: ValueRef, t: ty::t) { + add_clean_temp_mem_in_scope_(bcx, Some(scope_id), val, t); +} + +pub fn add_clean_temp_mem_in_scope_(bcx: block, scope_id: Option, + val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } debug!("add_clean_temp_mem(%s, %s, %s)", bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx())); let cleanup_type = cleanup_type(bcx.tcx(), t); - do in_scope_cx(bcx) |scope_info| { + do in_scope_cx(bcx, scope_id) |scope_info| { scope_info.cleanups.push(clean_temp(val, |a| glue::drop_ty(a, val, t), cleanup_type)); grow_scope_clean(scope_info); } } pub fn add_clean_return_to_mut(bcx: block, + scope_id: ast::node_id, root_key: root_map_key, frozen_val_ref: ValueRef, bits_val_ref: ValueRef, @@ -369,7 +380,7 @@ pub fn add_clean_return_to_mut(bcx: block, bcx.to_str(), bcx.val_to_str(frozen_val_ref), bcx.val_to_str(bits_val_ref)); - do in_scope_cx(bcx) |scope_info| { + do in_scope_cx(bcx, Some(scope_id)) |scope_info| { scope_info.cleanups.push( clean_temp( frozen_val_ref, @@ -390,7 +401,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { f } }; - do in_scope_cx(cx) |scope_info| { + do in_scope_cx(cx, None) |scope_info| { scope_info.cleanups.push(clean_temp(ptr, free_fn, normal_exit_and_unwind)); grow_scope_clean(scope_info); @@ -402,7 +413,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { // this will be more involved. For now, we simply zero out the local, and the // drop glue checks whether it is zero. pub fn revoke_clean(cx: block, val: ValueRef) { - do in_scope_cx(cx) |scope_info| { + do in_scope_cx(cx, None) |scope_info| { let cleanup_pos = scope_info.cleanups.iter().position_( |cu| match *cu { clean_temp(v, _, _) if v == val => true, @@ -419,27 +430,14 @@ pub fn revoke_clean(cx: block, val: ValueRef) { } pub fn block_cleanups(bcx: block) -> ~[cleanup] { - match bcx.kind { - block_non_scope => ~[], - block_scope(inf) => /*bad*/copy inf.cleanups + match bcx.scope { + None => ~[], + Some(inf) => /*bad*/copy inf.cleanups } } -pub enum block_kind { - // A scope at the end of which temporary values created inside of it are - // cleaned up. May correspond to an actual block in the language, but also - // to an implicit scope, for example, calls introduce an implicit scope in - // which the arguments are evaluated and cleaned up. - block_scope(@mut scope_info), - - // A non-scope block is a basic block created as a translation artifact - // from translating code that expresses conditional logic rather than by - // explicit { ... } block structure in the source language. It's called a - // non-scope block because it doesn't introduce a new variable scope. - block_non_scope, -} - pub struct scope_info { + parent: Option<@mut scope_info>, loop_break: Option, loop_label: Option, // A list of functions that must be run at when leaving this @@ -451,6 +449,8 @@ pub struct scope_info { cleanup_paths: ~[cleanup_path], // Unwinding landing pad. Also cleared when cleanups change. landing_pad: Option, + // info about the AST node this scope originated from, if any + node_info: Option, } impl scope_info { @@ -506,8 +506,8 @@ pub struct block_ { terminated: bool, unreachable: bool, parent: Option, - // The 'kind' of basic block this is. - kind: block_kind, + // The current scope within this basic block + scope: Option<@mut scope_info>, // Is this block part of a landing pad? is_lpad: bool, // info about the AST node this block originated from, if any @@ -517,7 +517,7 @@ pub struct block_ { fcx: fn_ctxt } -pub fn block_(llbb: BasicBlockRef, parent: Option, kind: block_kind, +pub fn block_(llbb: BasicBlockRef, parent: Option, is_lpad: bool, node_info: Option, fcx: fn_ctxt) -> block_ { @@ -526,7 +526,7 @@ pub fn block_(llbb: BasicBlockRef, parent: Option, kind: block_kind, terminated: false, unreachable: false, parent: parent, - kind: kind, + scope: None, is_lpad: is_lpad, node_info: node_info, fcx: fcx @@ -535,10 +535,10 @@ pub fn block_(llbb: BasicBlockRef, parent: Option, kind: block_kind, pub type block = @mut block_; -pub fn mk_block(llbb: BasicBlockRef, parent: Option, kind: block_kind, +pub fn mk_block(llbb: BasicBlockRef, parent: Option, is_lpad: bool, node_info: Option, fcx: fn_ctxt) -> block { - @mut block_(llbb, parent, kind, is_lpad, node_info, fcx) + @mut block_(llbb, parent, is_lpad, node_info, fcx) } pub struct Result { @@ -563,19 +563,33 @@ pub fn val_ty(v: ValueRef) -> Type { } } -pub fn in_scope_cx(cx: block, f: &fn(si: &mut scope_info)) { +pub fn in_scope_cx(cx: block, scope_id: Option, f: &fn(si: &mut scope_info)) { let mut cur = cx; + let mut cur_scope = cur.scope; loop { - match cur.kind { - block_scope(inf) => { - debug!("in_scope_cx: selected cur=%s (cx=%s)", - cur.to_str(), cx.to_str()); - f(inf); - return; + cur_scope = match cur_scope { + Some(inf) => match scope_id { + Some(wanted) => match inf.node_info { + Some(NodeInfo { id: actual, _ }) if wanted == actual => { + debug!("in_scope_cx: selected cur=%s (cx=%s)", + cur.to_str(), cx.to_str()); + f(inf); + return; + }, + _ => inf.parent, + }, + None => { + debug!("in_scope_cx: selected cur=%s (cx=%s)", + cur.to_str(), cx.to_str()); + f(inf); + return; + } + }, + None => { + cur = block_parent(cur); + cur.scope } - _ => () } - cur = block_parent(cur); } } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 75b1830778b1..db6a954ee911 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -249,42 +249,48 @@ pub fn trans_break_cont(bcx: block, let _icx = push_ctxt("trans_break_cont"); // Locate closest loop block, outputting cleanup as we go. let mut unwind = bcx; - let mut target; + let mut cur_scope = unwind.scope; + let mut target = unwind; + let mut quit = false; loop { - match unwind.kind { - block_scope(@scope_info { - loop_break: Some(brk), - loop_label: l, - _ - }) => { - // If we're looking for a labeled loop, check the label... - target = if to_end { - brk - } else { - unwind - }; - match opt_label { - Some(desired) => match l { - Some(actual) if actual == desired => break, - // If it doesn't match the one we want, - // don't break - _ => () - }, - None => break - } - } - _ => () + cur_scope = match cur_scope { + Some(@scope_info { + loop_break: Some(brk), + loop_label: l, + parent, + _ + }) => { + // If we're looking for a labeled loop, check the label... + target = if to_end { + brk + } else { + unwind + }; + match opt_label { + Some(desired) => match l { + Some(actual) if actual == desired => break, + // If it doesn't match the one we want, + // don't break + _ => parent, + }, + None => break, + } + } + Some(inf) => inf.parent, + None => { + unwind = match unwind.parent { + Some(bcx) => bcx, + // This is a return from a loop body block + None => { + Store(bcx, C_bool(!to_end), bcx.fcx.llretptr.get()); + cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn)); + Unreachable(bcx); + return bcx; + } + }; + unwind.scope + } } - unwind = match unwind.parent { - Some(bcx) => bcx, - // This is a return from a loop body block - None => { - Store(bcx, C_bool(!to_end), bcx.fcx.llretptr.get()); - cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn)); - Unreachable(bcx); - return bcx; - } - }; } cleanup_and_Br(bcx, unwind, target.llbb); Unreachable(bcx); diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs index 068ce4e2b33b..0db770b6c8bc 100644 --- a/src/librustc/middle/trans/write_guard.rs +++ b/src/librustc/middle/trans/write_guard.rs @@ -123,7 +123,7 @@ fn root(datum: &Datum, let scratch = scratch_datum(bcx, datum.ty, true); datum.copy_to_datum(bcx, INIT, scratch); let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); - add_clean_temp_mem(cleanup_bcx, scratch.val, scratch.ty); + add_clean_temp_mem_in_scope(cleanup_bcx, root_info.scope, scratch.val, scratch.ty); // Now, consider also freezing it. match root_info.freeze { @@ -168,7 +168,7 @@ fn root(datum: &Datum, } add_clean_return_to_mut( - cleanup_bcx, root_key, scratch.val, scratch_bits.val, + cleanup_bcx, root_info.scope, root_key, scratch.val, scratch_bits.val, filename, line); } }