#![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;
TrByCopy(llbinding) => {
let llval = Load(bcx, binding_info.llmatch);
let datum = Datum::new(llval, binding_info.ty, Lvalue);
+ call_lifetime_start(bcx, llbinding);
bcx = datum.store_to(bcx, llbinding);
+ match cs {
+ Some(cs) => bcx.fcx.schedule_lifetime_end(cs, llbinding),
+ _ => {}
+ }
llbinding
},
let datum = Datum::new(llval, binding_info.ty, Lvalue);
match cs {
- Some(cs) => bcx.fcx.schedule_drop_and_zero_mem(cs, llval, binding_info.ty),
+ Some(cs) => {
+ bcx.fcx.schedule_drop_and_zero_mem(cs, llval, binding_info.ty);
+ bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
+ }
_ => {}
}
let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr));
let val = val.to_llbool(bcx);
+ for (_, &binding_info) in data.bindings_map.iter() {
+ match binding_info.trmode {
+ TrByCopy(llbinding) => call_lifetime_end(bcx, llbinding),
+ _ => {}
+ }
+ }
+
return with_cond(bcx, Not(bcx, val), |bcx| {
// Guard does not match: remove all bindings from the lllocals table
for (_, &binding_info) in data.bindings_map.iter() {
+ call_lifetime_end(bcx, binding_info.llmatch);
bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
}
match chk {
let data = &m[0].data;
for &(ref ident, ref value_ptr) in m[0].bound_ptrs.iter() {
let llmatch = data.bindings_map.get(ident).llmatch;
+ call_lifetime_start(bcx, llmatch);
Store(bcx, *value_ptr, llmatch);
}
match data.arm.guard {
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) => {
- llmatch = alloca(bcx,
+ if !ty::type_moves_by_default(tcx, variable_ty) || reassigned => {
+ llmatch = alloca_no_lifetime(bcx,
llvariable_ty.ptr_to(),
"__llmatch");
- trmode = TrByCopy(alloca(bcx,
+ trmode = TrByCopy(alloca_no_lifetime(bcx,
llvariable_ty,
bcx.ident(ident).as_slice()));
}
// in this case, the final type of the variable will be T,
// but during matching we need to store a *T as explained
// above
- llmatch = alloca(bcx,
+ llmatch = alloca_no_lifetime(bcx,
llvariable_ty.ptr_to(),
bcx.ident(ident).as_slice());
trmode = TrByMove;
}
ast::BindByRef(_) => {
- llmatch = alloca(bcx,
+ llmatch = alloca_no_lifetime(bcx,
llvariable_ty,
bcx.ident(ident).as_slice());
trmode = TrByRef;
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() };
// to the default arm.
let has_default = arms.last().map_or(false, |arm| {
arm.pats.len() == 1
- && arm.pats.last().unwrap().node == ast::PatWild
+ && arm.pats.last().unwrap().node == ast::PatWild(ast::PatWildSingle)
});
compile_submatch(bcx, matches.as_slice(), [discr_datum.val], &chk, has_default);
}
}
+/// Generates code for the pattern binding in a `for` loop like
+/// `for <pat> in <expr> { ... }`.
+pub fn store_for_loop_binding<'a>(
+ bcx: &'a Block<'a>,
+ pat: Gc<ast::Pat>,
+ llvalue: ValueRef,
+ body_scope: cleanup::ScopeId)
+ -> &'a Block<'a> {
+ let _icx = push_ctxt("match::store_for_loop_binding");
+
+ if simple_identifier(&*pat).is_some() {
+ // Generate nicer LLVM for the common case of a `for` loop pattern
+ // like `for x in blahblah { ... }`.
+ let binding_type = node_id_type(bcx, pat.id);
+ bcx.fcx.lllocals.borrow_mut().insert(pat.id,
+ Datum::new(llvalue,
+ binding_type,
+ Lvalue));
+ return bcx
+ }
+
+ // General path. Copy out the values that are used in the pattern.
+ bind_irrefutable_pat(bcx, pat, llvalue, BindLocal, body_scope)
+}
+
fn mk_binding_alloca<'a,A>(bcx: &'a Block<'a>,
p_id: ast::NodeId,
ident: &ast::Ident,
ast::PatMac(..) => {
bcx.sess().span_bug(pat.span, "unexpanded macro");
}
- ast::PatWild | ast::PatWildMulti | ast::PatLit(_) | ast::PatRange(_, _) => ()
+ ast::PatWild(_) | ast::PatLit(_) | ast::PatRange(_, _) => ()
}
return bcx;
}