#![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;
trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest)
}
-fn create_bindings_map(bcx: &Block, pat: Gc<ast::Pat>) -> 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<ast::Pat>,
+ 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;
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");
let arm_datas: Vec<ArmData> = 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() };