X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc%2Fmiddle%2Ftrans%2F_match.rs;h=d8cbf5a2341e57c3e550afa2792a9c523f0421f1;hb=d7c0f7d1c07a060b6d06bdd60b24c78bd2c9a6c3;hp=5334205aa52347b1d9d62fff9ac1477b45966c97;hpb=4879ca79240387d18723a324d92c603c5057d342;p=rust.git diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 5334205aa52..d8cbf5a2341 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -189,7 +189,9 @@ #![allow(non_camel_case_types)] use back::abi; +use mc = middle::mem_categorization; use driver::config::FullDebugInfo; +use euv = middle::expr_use_visitor; use llvm; use llvm::{ValueRef, BasicBlockRef}; use middle::const_eval; @@ -1292,13 +1294,55 @@ pub fn trans_match<'a>( trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest) } -fn create_bindings_map(bcx: &Block, pat: Gc) -> BindingsMap { +/// Checks whether the binding in `discr` is assigned to anywhere in the expression `body` +fn is_discr_reassigned(bcx: &Block, discr: &ast::Expr, body: &ast::Expr) -> bool { + match discr.node { + ast::ExprPath(..) => match bcx.def(discr.id) { + def::DefLocal(vid, _) | def::DefBinding(vid, _) => { + let mut rc = ReassignmentChecker { + node: vid, + reassigned: false + }; + { + let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx); + visitor.walk_expr(body); + } + rc.reassigned + } + _ => false + }, + _ => false + } +} + +struct ReassignmentChecker { + node: ast::NodeId, + reassigned: bool +} + +impl euv::Delegate for ReassignmentChecker { + fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {} + fn consume_pat(&mut self, _: &ast::Pat, _: mc::cmt, _: euv::ConsumeMode) {} + fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region, + _: ty::BorrowKind, _: euv::LoanCause) {} + fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} + fn mutate(&mut self, _: ast::NodeId, _: Span, cmt: mc::cmt, _: euv::MutateMode) { + match cmt.cat { + mc::cat_local(vid) => self.reassigned = self.node == vid, + _ => {} + } + } +} + +fn create_bindings_map(bcx: &Block, pat: Gc, + discr: &ast::Expr, body: &ast::Expr) -> BindingsMap { // Create the bindings map, which is a mapping from each binding name // to an alloca() that will be the value for that local variable. // Note that we use the names because each binding will have many ids // from the various alternatives. let ccx = bcx.ccx(); let tcx = bcx.tcx(); + let reassigned = is_discr_reassigned(bcx, discr, body); let mut bindings_map = HashMap::new(); pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| { let ident = path1.node; @@ -1310,7 +1354,7 @@ fn create_bindings_map(bcx: &Block, pat: Gc) -> BindingsMap { let trmode; match bm { ast::BindByValue(_) - if !ty::type_moves_by_default(tcx, variable_ty) => { + if !ty::type_moves_by_default(tcx, variable_ty) || reassigned => { llmatch = alloca_no_lifetime(bcx, llvariable_ty.ptr_to(), "__llmatch"); @@ -1371,7 +1415,7 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>, let arm_datas: Vec = arms.iter().map(|arm| ArmData { bodycx: fcx.new_id_block("case_body", arm.body.id), arm: arm, - bindings_map: create_bindings_map(bcx, *arm.pats.get(0)) + bindings_map: create_bindings_map(bcx, *arm.pats.get(0), discr_expr, &*arm.body) }).collect(); let mut static_inliner = StaticInliner { tcx: scope_cx.tcx() };