rm obsolete for support from the compiler

This commit is contained in:
Daniel Micay 2013-08-03 23:51:29 -04:00
parent 1008945528
commit e7bb33aed8
20 changed files with 15 additions and 323 deletions

View File

@ -396,7 +396,6 @@ impl CFGBuilder {
}
ast::expr_addr_of(_, e) |
ast::expr_loop_body(e) |
ast::expr_do_body(e) |
ast::expr_cast(e, _) |
ast::expr_unary(_, _, e) |

View File

@ -45,14 +45,6 @@ pub fn check_crate(tcx: ty::ctxt, crate: &Crate) {
can_ret: false
}, v));
}
expr_loop_body(@expr {node: expr_fn_block(_, ref b), _}) => {
let sigil = ty::ty_closure_sigil(ty::expr_ty(tcx, e));
let blk = (sigil == BorrowedSigil);
(v.visit_block)(b, (Context {
in_loop: true,
can_ret: blk
}, v));
}
expr_break(_) => {
if !cx.in_loop {
tcx.sess.span_err(e.span, "`break` outside of loop");

View File

@ -82,19 +82,8 @@ struct PropagationContext<'self, O> {
changed: bool
}
#[deriving(Eq)]
enum LoopKind {
/// A `while` or `loop` loop
TrueLoop,
/// A `for` "loop" (i.e., really a func call where `break`, `return`,
/// and `loop` all essentially perform an early return from the closure)
ForLoop
}
struct LoopScope<'self> {
loop_id: ast::NodeId,
loop_kind: LoopKind,
break_bits: ~[uint]
}
@ -509,7 +498,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
loop_scopes.push(LoopScope {
loop_id: expr.id,
loop_kind: ForLoop,
break_bits: reslice(in_out).to_owned()
});
for input in decl.inputs.iter() {
@ -574,7 +562,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
let mut body_bits = reslice(in_out).to_owned();
loop_scopes.push(LoopScope {
loop_id: expr.id,
loop_kind: TrueLoop,
break_bits: reslice(in_out).to_owned()
});
self.walk_block(blk, body_bits, loop_scopes);
@ -599,7 +586,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
self.reset(in_out);
loop_scopes.push(LoopScope {
loop_id: expr.id,
loop_kind: TrueLoop,
break_bits: reslice(in_out).to_owned()
});
self.walk_block(blk, body_bits, loop_scopes);
@ -646,20 +632,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
ast::expr_ret(o_e) => {
self.walk_opt_expr(o_e, in_out, loop_scopes);
// is this a return from a `for`-loop closure?
match loop_scopes.iter().position(|s| s.loop_kind == ForLoop) {
Some(i) => {
// if so, add the in_out bits to the state
// upon exit. Remember that we cannot count
// upon the `for` loop function not to invoke
// the closure again etc.
self.break_from_to(expr, &mut loop_scopes[i], in_out);
}
None => {}
}
self.reset(in_out);
}
@ -671,22 +643,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
ast::expr_again(label) => {
let scope = self.find_scope(expr, label, loop_scopes);
match scope.loop_kind {
TrueLoop => {
self.pop_scopes(expr, scope, in_out);
self.add_to_entry_set(scope.loop_id, reslice(in_out));
}
ForLoop => {
// If this `loop` construct is looping back to a `for`
// loop, then `loop` is really just a return from the
// closure. Therefore, we treat it the same as `break`.
// See case for `expr_fn_block` for more details.
self.break_from_to(expr, scope, in_out);
}
}
self.pop_scopes(expr, scope, in_out);
self.add_to_entry_set(scope.loop_id, reslice(in_out));
self.reset(in_out);
}
@ -756,7 +714,6 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
}
ast::expr_addr_of(_, e) |
ast::expr_loop_body(e) |
ast::expr_do_body(e) |
ast::expr_cast(e, _) |
ast::expr_unary(_, _, e) |

View File

@ -512,7 +512,7 @@ fn visit_expr(expr: @expr, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
// otherwise, live nodes are not required:
expr_index(*) | expr_field(*) | expr_vstore(*) | expr_vec(*) |
expr_call(*) | expr_method_call(*) | expr_tup(*) | expr_log(*) |
expr_binary(*) | expr_addr_of(*) | expr_loop_body(*) |
expr_binary(*) | expr_addr_of(*) |
expr_do_body(*) | expr_cast(*) | expr_unary(*) | expr_break(_) |
expr_again(_) | expr_lit(_) | expr_ret(*) | expr_block(*) |
expr_assign(*) | expr_assign_op(*) | expr_mac(*) |
@ -1209,7 +1209,6 @@ impl Liveness {
}
expr_addr_of(_, e) |
expr_loop_body(e) |
expr_do_body(e) |
expr_cast(e, _) |
expr_unary(_, _, e) |
@ -1483,7 +1482,7 @@ fn check_expr(expr: @expr, (this, vt): (@Liveness, vt<@Liveness>)) {
expr_call(*) | expr_method_call(*) | expr_if(*) | expr_match(*) |
expr_while(*) | expr_loop(*) | expr_index(*) | expr_field(*) |
expr_vstore(*) | expr_vec(*) | expr_tup(*) | expr_log(*) |
expr_binary(*) | expr_loop_body(*) | expr_do_body(*) |
expr_binary(*) | expr_do_body(*) |
expr_cast(*) | expr_unary(*) | expr_ret(*) | expr_break(*) |
expr_again(*) | expr_lit(_) | expr_block(*) |
expr_mac(*) | expr_addr_of(*) | expr_struct(*) | expr_repeat(*) |

View File

@ -423,7 +423,7 @@ impl mem_categorization_ctxt {
ast::expr_addr_of(*) | ast::expr_call(*) |
ast::expr_assign(*) | ast::expr_assign_op(*) |
ast::expr_fn_block(*) | ast::expr_ret(*) | ast::expr_loop_body(*) |
ast::expr_fn_block(*) | ast::expr_ret(*) |
ast::expr_do_body(*) | ast::expr_unary(*) |
ast::expr_method_call(*) | ast::expr_cast(*) | ast::expr_vstore(*) |
ast::expr_vec(*) | ast::expr_tup(*) | ast::expr_if(*) |

View File

@ -541,7 +541,6 @@ impl VisitContext {
self.consume_expr(count, visitor);
}
expr_loop_body(base) |
expr_do_body(base) => {
self.use_expr(base, comp_mode, visitor);
}

View File

@ -41,7 +41,6 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
ty::ByCopy,
out,
&mut cleanups,
None,
callee::DontAutorefArg)
}));
@ -56,7 +55,6 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
ty::ByCopy,
e,
&mut cleanups,
None,
callee::DontAutorefArg)
})
@ -77,7 +75,6 @@ pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
ty::ByCopy,
input,
&mut cleanups,
None,
callee::DontAutorefArg)
})

View File

@ -27,7 +27,6 @@ use middle::trans::base;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::closure;
use middle::trans::common;
use middle::trans::common::*;
use middle::trans::datum::*;
@ -556,29 +555,9 @@ pub fn trans_call_inner(in_cx: @mut Block,
autoref_arg: AutorefArg)
-> Result {
do base::with_scope_result(in_cx, call_info, "call") |cx| {
let ret_in_loop = match args {
ArgExprs(args) => {
args.len() > 0u && match args.last().node {
ast::expr_loop_body(@ast::expr {
node: ast::expr_fn_block(_, ref body),
_
}) => body_contains_ret(body),
_ => false
}
}
_ => false
};
let callee = get_callee(cx);
let mut bcx = callee.bcx;
let ccx = cx.ccx();
let ret_flag = if ret_in_loop {
let flag = alloca(bcx, Type::bool(), "__ret_flag");
Store(bcx, C_bool(false), flag);
Some(flag)
} else {
None
};
let (llfn, llenv) = unsafe {
match callee.data {
@ -611,9 +590,7 @@ pub fn trans_call_inner(in_cx: @mut Block,
}
llargs.push(llenv);
bcx = trans_args(bcx, args, fn_expr_ty,
ret_flag, autoref_arg, &mut llargs);
bcx = trans_args(bcx, args, fn_expr_ty, autoref_arg, &mut llargs);
// Now that the arguments have finished evaluating, we need to revoke
// the cleanup for the self argument
@ -667,20 +644,6 @@ pub fn trans_call_inner(in_cx: @mut Block,
if ty::type_is_bot(ret_ty) {
Unreachable(bcx);
} else if ret_in_loop {
let ret_flag_result = bool_to_i1(bcx, Load(bcx, ret_flag.get()));
bcx = do with_cond(bcx, ret_flag_result) |bcx| {
{
let r = bcx.fcx.loop_ret;
for &(flagptr, _) in r.iter() {
Store(bcx, C_bool(true), flagptr);
Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
}
}
base::cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
Unreachable(bcx);
bcx
}
}
rslt(bcx, llresult)
}
@ -713,7 +676,6 @@ pub fn trans_ret_slot(bcx: @mut Block, fn_ty: ty::t, dest: Option<expr::Dest>)
pub fn trans_args(cx: @mut Block,
args: CallArgs,
fn_ty: ty::t,
ret_flag: Option<ValueRef>,
autoref_arg: AutorefArg,
llargs: &mut ~[ValueRef]) -> @mut Block
{
@ -728,7 +690,6 @@ pub fn trans_args(cx: @mut Block,
// to cast her view of the arguments to the caller's view.
match args {
ArgExprs(arg_exprs) => {
let last = arg_exprs.len() - 1u;
for (i, arg_expr) in arg_exprs.iter().enumerate() {
let arg_val = unpack_result!(bcx, {
trans_arg_expr(bcx,
@ -736,7 +697,6 @@ pub fn trans_args(cx: @mut Block,
ty::ByCopy,
*arg_expr,
&mut temp_cleanups,
if i == last { ret_flag } else { None },
autoref_arg)
});
llargs.push(arg_val);
@ -769,49 +729,17 @@ pub fn trans_arg_expr(bcx: @mut Block,
self_mode: ty::SelfMode,
arg_expr: @ast::expr,
temp_cleanups: &mut ~[ValueRef],
ret_flag: Option<ValueRef>,
autoref_arg: AutorefArg) -> Result {
let _icx = push_ctxt("trans_arg_expr");
let ccx = bcx.ccx();
debug!("trans_arg_expr(formal_arg_ty=(%s), self_mode=%?, arg_expr=%s, \
ret_flag=%?)",
debug!("trans_arg_expr(formal_arg_ty=(%s), self_mode=%?, arg_expr=%s)",
formal_arg_ty.repr(bcx.tcx()),
self_mode,
arg_expr.repr(bcx.tcx()),
ret_flag.map(|v| bcx.val_to_str(*v)));
arg_expr.repr(bcx.tcx()));
// translate the arg expr to a datum
let arg_datumblock = match ret_flag {
None => expr::trans_to_datum(bcx, arg_expr),
// If there is a ret_flag, this *must* be a loop body
Some(_) => {
match arg_expr.node {
ast::expr_loop_body(
blk @ @ast::expr {
node: ast::expr_fn_block(ref decl, ref body),
_
}) => {
let scratch_ty = expr_ty(bcx, arg_expr);
let scratch = alloc_ty(bcx, scratch_ty, "__ret_flag");
let arg_ty = expr_ty(bcx, arg_expr);
let sigil = ty::ty_closure_sigil(arg_ty);
let bcx = closure::trans_expr_fn(
bcx, sigil, decl, body, arg_expr.id,
blk.id, Some(ret_flag), expr::SaveIn(scratch));
DatumBlock {bcx: bcx,
datum: Datum {val: scratch,
ty: scratch_ty,
mode: ByRef(RevokeClean)}}
}
_ => {
bcx.sess().impossible_case(
arg_expr.span, "ret_flag with non-loop-body expr");
}
}
}
};
let arg_datumblock = expr::trans_to_datum(bcx, arg_expr);
let arg_datum = arg_datumblock.datum;
let bcx = arg_datumblock.bcx;

View File

@ -605,27 +605,6 @@ fn trans_rvalue_dps_unadjusted(bcx: @mut Block, expr: @ast::expr,
expr.id, expr.id,
None, dest);
}
ast::expr_loop_body(blk) => {
let expr_ty = expr_ty(bcx, expr);
let sigil = ty::ty_closure_sigil(expr_ty);
match blk.node {
ast::expr_fn_block(ref decl, ref body) => {
return closure::trans_expr_fn(bcx,
sigil,
decl,
body,
expr.id,
blk.id,
Some(None),
dest);
}
_ => {
bcx.sess().impossible_case(
expr.span,
"loop_body has the wrong kind of contents")
}
}
}
ast::expr_do_body(blk) => {
return trans_into(bcx, blk, dest);
}

View File

@ -137,7 +137,6 @@ pub fn trans_self_arg(bcx: @mut Block,
mentry.self_mode,
base,
temp_cleanups,
None,
DontAutorefArg)
}

View File

@ -400,7 +400,7 @@ pub fn mark_for_expr(cx: &Context, e: &expr) {
expr_match(*) | expr_block(_) | expr_if(*) | expr_while(*) |
expr_break(_) | expr_again(_) | expr_unary(*) | expr_lit(_) |
expr_mac(_) | expr_addr_of(*) | expr_ret(_) | expr_loop(*) |
expr_loop_body(_) | expr_do_body(_) => (),
expr_do_body(_) => (),
expr_for_loop(*) => fail!("non-desugared expr_for_loop")
}

View File

@ -3192,7 +3192,6 @@ pub fn expr_kind(tcx: ctxt,
ast::expr_if(*) |
ast::expr_match(*) |
ast::expr_fn_block(*) |
ast::expr_loop_body(*) |
ast::expr_do_body(*) |
ast::expr_block(*) |
ast::expr_repeat(*) |

View File

@ -170,10 +170,6 @@ pub struct inherited {
#[deriving(Clone)]
pub enum FnKind {
// This is a for-closure. The ty::t is the return type of the
// enclosing function.
ForLoop(ty::t),
// A do-closure.
DoBlock,
@ -230,8 +226,6 @@ pub struct FnCtxt {
err_count_on_creation: uint,
ret_ty: ty::t,
// Used by loop bodies that return from the outer function
indirect_ret_ty: Option<ty::t>,
ps: PurityState,
// Sometimes we generate region pointers where the precise region
@ -283,7 +277,6 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
@mut FnCtxt {
err_count_on_creation: ccx.tcx.sess.err_count(),
ret_ty: rty,
indirect_ret_ty: None,
ps: PurityState::function(ast::impure_fn, 0),
region_lb: region_bnd,
in_scope_regions: @Nil,
@ -390,17 +383,9 @@ pub fn check_fn(ccx: @mut CrateCtxt,
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let fcx: @mut FnCtxt = {
// In a for-loop, you have an 'indirect return' because return
// does not return out of the directly enclosing fn
let indirect_ret_ty = match fn_kind {
ForLoop(t) => Some(t),
DoBlock | Vanilla => None
};
@mut FnCtxt {
err_count_on_creation: err_count_on_creation,
ret_ty: ret_ty,
indirect_ret_ty: indirect_ret_ty,
ps: PurityState::function(purity, id),
region_lb: body.id,
in_scope_regions: isr,
@ -958,11 +943,6 @@ impl FnCtxt {
return;
}
match self.fn_kind {
ForLoop(_) if !ty::type_is_bool(e) && !ty::type_is_nil(a) =>
self.tcx().sess.span_err(sp, fmt!("A for-loop body must \
return (), but it returns %s here. \
Perhaps you meant to write a `do`-block?",
ppaux::ty_to_str(self.tcx(), a))),
DoBlock if ty::type_is_bool(e) && ty::type_is_nil(a) =>
// If we expected bool and got ()...
self.tcx().sess.span_err(sp, fmt!("Do-block body must \
@ -1274,7 +1254,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
for (i, arg) in args.iter().enumerate() {
let is_block = match arg.node {
ast::expr_fn_block(*) | ast::expr_loop_body(*) |
ast::expr_fn_block(*) |
ast::expr_do_body(*) => true,
_ => false
};
@ -2126,121 +2106,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
fcx.write_ty(id, enum_type);
}
fn check_loop_body(fcx: @mut FnCtxt,
expr: @ast::expr,
expected: Option<ty::t>,
loop_body: @ast::expr) {
// a loop body is the special argument to a `for` loop. We know that
// there will be an expected type in this context because it can only
// appear in the context of a call, so we get the expected type of the
// parameter. The catch here is that we need to validate two things:
// 1. a closure that returns a bool is expected
// 2. the closure that was given returns unit
let tcx = fcx.tcx();
let mut err_happened = false;
let expected_sty = unpack_expected(fcx,
expected,
|x| Some((*x).clone()));
let inner_ty = match expected_sty {
Some(ty::ty_closure(ref fty)) => {
match fcx.mk_subty(false, infer::Misc(expr.span),
fty.sig.output, ty::mk_bool()) {
result::Ok(_) => {
ty::mk_closure(tcx, ty::ClosureTy {
sig: FnSig {
output: ty::mk_nil(),
..fty.sig.clone()
},
..(*fty).clone()
})
}
result::Err(_) => {
fcx.type_error_message(
expr.span,
|actual| {
let did_you_mean = {
if ty::type_is_nil(fty.sig.output) {
"\nDid you mean to use \
`do` instead of `for`?"
} else {
""
}
};
fmt!("A `for` loop iterator should expect a \
closure that returns `bool`. This \
iterator expects a closure that \
returns `%s`.%s",
actual, did_you_mean)
},
fty.sig.output,
None);
err_happened = true;
fcx.write_error(expr.id);
ty::mk_err()
}
}
}
_ => {
match expected {
Some(expected_t) => {
fcx.type_error_message(
expr.span,
|actual| {
fmt!("last argument in `for` call \
has non-closure type: %s",
actual)
},
expected_t, None);
let err_ty = ty::mk_err();
fcx.write_error(expr.id);
err_happened = true;
err_ty
}
None => fcx.tcx().sess.impossible_case(
expr.span,
"loop body must have an expected type")
}
}
};
match loop_body.node {
ast::expr_fn_block(ref decl, ref body) => {
// If an error occurred, we pretend this isn't a for
// loop, so as to assign types to all nodes while also
// propagating ty_err throughout so as to suppress
// derived errors. If we passed in ForLoop in the
// error case, we'd potentially emit a spurious error
// message because of the indirect_ret_ty.
let fn_kind = if err_happened {
Vanilla
} else {
let indirect_ret_ty =
fcx.indirect_ret_ty.get_or_default(fcx.ret_ty);
ForLoop(indirect_ret_ty)
};
check_expr_fn(fcx, loop_body, None,
decl, body, fn_kind, Some(inner_ty));
demand::suptype(fcx, loop_body.span,
inner_ty, fcx.expr_ty(loop_body));
}
ref n => {
fail!("check_loop_body expected expr_fn_block, not %?", n)
}
}
let block_ty = structurally_resolved_type(
fcx, expr.span, fcx.node_ty(loop_body.id));
if err_happened {
fcx.write_error(expr.id);
fcx.write_error(loop_body.id);
} else {
let loop_body_ty =
ty::replace_closure_return_type(
tcx, block_ty, ty::mk_bool());
fcx.write_ty(expr.id, loop_body_ty);
}
}
let tcx = fcx.ccx.tcx;
let id = expr.id;
match expr.node {
@ -2494,9 +2359,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
ast::expr_break(_) => { fcx.write_bot(id); }
ast::expr_again(_) => { fcx.write_bot(id); }
ast::expr_ret(expr_opt) => {
let ret_ty = match fcx.indirect_ret_ty {
Some(t) => t, None => fcx.ret_ty
};
let ret_ty = fcx.ret_ty;
match expr_opt {
None => match fcx.mk_eqty(false, infer::Misc(expr.span),
ret_ty, ty::mk_nil()) {
@ -2581,9 +2444,6 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
check_expr_fn(fcx, expr, None,
decl, body, Vanilla, expected);
}
ast::expr_loop_body(loop_body) => {
check_loop_body(fcx, expr, expected, loop_body);
}
ast::expr_do_body(b) => {
let expected_sty = unpack_expected(fcx,
expected,

View File

@ -426,10 +426,6 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
oldvisit::visit_expr(expr, (rcx, v));
}
ast::expr_loop_body(subexpr) => {
check_expr_fn_block(rcx, subexpr, v, true);
}
ast::expr_fn_block(*) => {
check_expr_fn_block(rcx, expr, v, false);
}
@ -1031,7 +1027,6 @@ pub mod guarantor {
ast::expr_if(*) |
ast::expr_match(*) |
ast::expr_fn_block(*) |
ast::expr_loop_body(*) |
ast::expr_do_body(*) |
ast::expr_block(*) |
ast::expr_repeat(*) |

View File

@ -70,8 +70,7 @@ pub fn loop_query(b: &ast::Block, p: @fn(&ast::expr_) -> bool) -> bool {
match e.node {
// Skip inner loops, since a break in the inner loop isn't a
// break inside the outer loop
ast::expr_loop(*) | ast::expr_while(*)
| ast::expr_loop_body(*) => {}
ast::expr_loop(*) | ast::expr_while(*) => {}
_ => oldvisit::visit_expr(e, (flag, v))
}
};

View File

@ -472,11 +472,6 @@ pub enum expr_ {
expr_loop(Block, Option<ident>),
expr_match(@expr, ~[arm]),
expr_fn_block(fn_decl, Block),
// Inner expr is always an expr_fn_block. We need the wrapping node to
// easily type this (a function returning nil on the inside but bool on
// the outside).
expr_loop_body(@expr),
// Like expr_loop_body but for 'do' blocks
expr_do_body(@expr),
expr_block(Block),

View File

@ -541,7 +541,6 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
fld.fold_expr(ohs)
)
}
expr_loop_body(f) => expr_loop_body(fld.fold_expr(f)),
expr_do_body(f) => expr_do_body(fld.fold_expr(f)),
expr_lit(_) => (*e).clone(),
expr_cast(expr, ref ty) => {

View File

@ -501,7 +501,7 @@ pub fn visit_expr<E:Clone>(ex: @expr, (e, v): (E, vt<E>)) {
(v.visit_expr)(b, (e.clone(), v));
}
expr_addr_of(_, x) | expr_unary(_, _, x) |
expr_loop_body(x) | expr_do_body(x) => (v.visit_expr)(x, (e.clone(), v)),
expr_do_body(x) => (v.visit_expr)(x, (e.clone(), v)),
expr_lit(_) => (),
expr_cast(x, ref t) => {
(v.visit_expr)(x, (e.clone(), v));

View File

@ -1087,7 +1087,7 @@ pub fn print_call_post(s: @ps,
nbsp(s);
match blk.get().node {
// need to handle closures specifically
ast::expr_do_body(e) | ast::expr_loop_body(e) => {
ast::expr_do_body(e) => {
end(s); // we close our head box; closure
// will create it's own.
print_expr(s, e);
@ -1338,9 +1338,6 @@ pub fn print_expr(s: @ps, expr: &ast::expr) {
// empty box to satisfy the close.
ibox(s, 0);
}
ast::expr_loop_body(body) => {
print_expr(s, body);
}
ast::expr_do_body(body) => {
print_expr(s, body);
}

View File

@ -513,7 +513,6 @@ pub fn visit_expr<E:Clone>(visitor: @Visitor<E>, expression: @expr, env: E) {
}
expr_addr_of(_, subexpression) |
expr_unary(_, _, subexpression) |
expr_loop_body(subexpression) |
expr_do_body(subexpression) => {
visitor.visit_expr(subexpression, env.clone())
}