}
fn visit_local(&mut self,
- _local: & $($mutability)* Local) {
+ _local: & $($mutability)* Local,
+ _context: LvalueContext<'tcx>,
+ _location: Location) {
}
fn visit_visibility_scope(&mut self,
location: Location) {
match *lvalue {
Lvalue::Local(ref $($mutability)* local) => {
- self.visit_local(local);
+ self.visit_local(local, context, location);
}
Lvalue::Static(ref $($mutability)* static_) => {
self.visit_static(static_, context, location);
}
// Replace all uses of the destination local with the source local.
- let src_lvalue = Lvalue::Local(src_local);
- def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
+ def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_local);
// Finally, zap the now-useless assignment instruction.
debug!(" Deleting assignment");
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
fn visit_local(&mut self,
- local: &mut Local) {
+ local: &mut Local,
+ _: LvalueContext<'tcx>,
+ _: Location) {
if *local == self.from {
*local = self.to;
}
struct DerefArgVisitor;
impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
+ fn visit_local(&mut self,
+ local: &mut Local,
+ _: LvalueContext<'tcx>,
+ _: Location) {
+ assert_ne!(*local, self_arg());
+ }
+
fn visit_lvalue(&mut self,
lvalue: &mut Lvalue<'tcx>,
context: LvalueContext<'tcx>,
}
impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
+ fn visit_local(&mut self,
+ local: &mut Local,
+ _: LvalueContext<'tcx>,
+ _: Location) {
+ assert_eq!(self.remap.get(local), None);
+ }
+
fn visit_lvalue(&mut self,
lvalue: &mut Lvalue<'tcx>,
context: LvalueContext<'tcx>,
new
}
- fn update_local(&self, local: Local) -> Option<Local> {
- let idx = local.index();
- if idx < (self.args.len() + 1) {
- return None;
- }
- let idx = idx - (self.args.len() + 1);
- let local = Local::new(idx);
- self.local_map.get(local).cloned()
- }
-
fn arg_index(&self, arg: Local) -> Option<usize> {
let idx = arg.index();
if idx > 0 && idx <= self.args.len() {
}
impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+ fn visit_local(&mut self,
+ local: &mut Local,
+ _ctxt: LvalueContext<'tcx>,
+ _location: Location) {
+ if *local == RETURN_POINTER {
+ match self.destination {
+ Lvalue::Local(l) => *local = l,
+ ref lval => bug!("Return lvalue is {:?}, not local", lval)
+ }
+ }
+ let idx = local.index() - 1;
+ if idx < self.args.len() {
+ match self.args[idx] {
+ Operand::Consume(Lvalue::Local(l)) => *local = l,
+ ref op => bug!("Arg operand `{:?}` is {:?}, not local", idx, op)
+ }
+ }
+ *local = self.local_map[Local::new(idx - self.args.len())];
+ }
+
fn visit_lvalue(&mut self,
lvalue: &mut Lvalue<'tcx>,
_ctxt: LvalueContext<'tcx>,
_location: Location) {
- if let Lvalue::Local(ref mut local) = *lvalue {
- if let Some(l) = self.update_local(*local) {
- // Temp or Var; update the local reference
- *local = l;
- return;
- }
- }
- if let Lvalue::Local(local) = *lvalue {
- if local == RETURN_POINTER {
- // Return pointer; update the lvalue itself
- *lvalue = self.destination.clone();
- } else if local.index() < (self.args.len() + 1) {
- // Argument, once again update the the lvalue itself
- let idx = local.index() - 1;
- if let Operand::Consume(ref lval) = self.args[idx] {
- *lvalue = lval.clone();
- } else {
- bug!("Arg operand `{:?}` is not an Lvalue use.", idx)
- }
- }
+ if let Lvalue::Local(RETURN_POINTER) = *lvalue {
+ // Return pointer; update the lvalue itself
+ *lvalue = self.destination.clone();
} else {
- self.super_lvalue(lvalue, _ctxt, _location)
+ self.super_lvalue(lvalue, _ctxt, _location);
}
}
}
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
- fn visit_lvalue(&mut self,
- lvalue: &Lvalue<'tcx>,
- context: LvalueContext<'tcx>,
- location: Location) {
- self.super_lvalue(lvalue, context, location);
- if let Lvalue::Local(index) = *lvalue {
- // We're only interested in temporaries
- if self.mir.local_kind(index) != LocalKind::Temp {
- return;
- }
+ fn visit_local(&mut self,
+ &index: &Local,
+ context: LvalueContext<'tcx>,
+ location: Location) {
+ // We're only interested in temporaries
+ if self.mir.local_kind(index) != LocalKind::Temp {
+ return;
+ }
- // Ignore drops, if the temp gets promoted,
- // then it's constant and thus drop is noop.
- // Storage live ranges are also irrelevant.
- if context.is_drop() || context.is_storage_marker() {
- return;
- }
+ // Ignore drops, if the temp gets promoted,
+ // then it's constant and thus drop is noop.
+ // Storage live ranges are also irrelevant.
+ if context.is_drop() || context.is_storage_marker() {
+ return;
+ }
- let temp = &mut self.temps[index];
- if *temp == TempState::Undefined {
- match context {
- LvalueContext::Store |
- LvalueContext::Call => {
- *temp = TempState::Defined {
- location,
- uses: 0
- };
- return;
- }
- _ => { /* mark as unpromotable below */ }
- }
- } else if let TempState::Defined { ref mut uses, .. } = *temp {
- // We always allow borrows, even mutable ones, as we need
- // to promote mutable borrows of some ZSTs e.g. `&mut []`.
- let allowed_use = match context {
- LvalueContext::Borrow {..} => true,
- _ => context.is_nonmutating_use()
- };
- if allowed_use {
- *uses += 1;
+ let temp = &mut self.temps[index];
+ if *temp == TempState::Undefined {
+ match context {
+ LvalueContext::Store |
+ LvalueContext::Call => {
+ *temp = TempState::Defined {
+ location,
+ uses: 0
+ };
return;
}
- /* mark as unpromotable below */
+ _ => { /* mark as unpromotable below */ }
}
- *temp = TempState::Unpromotable;
+ } else if let TempState::Defined { ref mut uses, .. } = *temp {
+ // We always allow borrows, even mutable ones, as we need
+ // to promote mutable borrows of some ZSTs e.g. `&mut []`.
+ let allowed_use = match context {
+ LvalueContext::Borrow {..} => true,
+ _ => context.is_nonmutating_use()
+ };
+ if allowed_use {
+ *uses += 1;
+ return;
+ }
+ /* mark as unpromotable below */
}
+ *temp = TempState::Unpromotable;
}
fn visit_source_info(&mut self, source_info: &SourceInfo) {
/// Replaces all temporaries with their promoted counterparts.
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
- fn visit_lvalue(&mut self,
- lvalue: &mut Lvalue<'tcx>,
- context: LvalueContext<'tcx>,
- location: Location) {
- if let Lvalue::Local(ref mut temp) = *lvalue {
- if self.source.local_kind(*temp) == LocalKind::Temp {
- *temp = self.promote_temp(*temp);
- }
+ fn visit_local(&mut self,
+ local: &mut Local,
+ _: LvalueContext<'tcx>,
+ _: Location) {
+ if self.source.local_kind(*local) == LocalKind::Temp {
+ *local = self.promote_temp(*local);
}
- self.super_lvalue(lvalue, context, location);
}
}
/// For functions (constant or not), it also records
/// candidates for promotion in promotion_candidates.
impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
+ fn visit_local(&mut self,
+ &local: &Local,
+ _: LvalueContext<'tcx>,
+ _: Location) {
+ match self.mir.local_kind(local) {
+ LocalKind::ReturnPointer => {
+ self.not_const();
+ }
+ LocalKind::Arg => {
+ self.add(Qualif::FN_ARGUMENT);
+ }
+ LocalKind::Var => {
+ self.add(Qualif::NOT_CONST);
+ }
+ LocalKind::Temp => {
+ if !self.temp_promotion_state[local].is_promotable() {
+ self.add(Qualif::NOT_PROMOTABLE);
+ }
+
+ if let Some(qualif) = self.temp_qualif[local] {
+ self.add(qualif);
+ } else {
+ self.not_const();
+ }
+ }
+ }
+ }
+
fn visit_lvalue(&mut self,
lvalue: &Lvalue<'tcx>,
context: LvalueContext<'tcx>,
location: Location) {
match *lvalue {
- Lvalue::Local(local) => match self.mir.local_kind(local) {
- LocalKind::ReturnPointer => {
- self.not_const();
- }
- LocalKind::Arg => {
- self.add(Qualif::FN_ARGUMENT);
- }
- LocalKind::Var => {
- self.add(Qualif::NOT_CONST);
- }
- LocalKind::Temp => {
- if !self.temp_promotion_state[local].is_promotable() {
- self.add(Qualif::NOT_PROMOTABLE);
- }
-
- if let Some(qualif) = self.temp_qualif[local] {
- self.add(qualif);
- } else {
- self.not_const();
- }
- }
- },
+ Lvalue::Local(ref local) => self.visit_local(local, context, location),
Lvalue::Static(ref global) => {
self.add(Qualif::STATIC);
}
impl<'tcx> Visitor<'tcx> for DeclMarker {
- fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
- if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead {
- // ignore these altogether, they get removed along with their otherwise unused decls.
- return;
+ fn visit_local(&mut self, local: &Local, ctx: LvalueContext<'tcx>, _: Location) {
+ // ignore these altogether, they get removed along with their otherwise unused decls.
+ if ctx != LvalueContext::StorageLive && ctx != LvalueContext::StorageDead {
+ self.locals.insert(local.index());
}
- if let Lvalue::Local(ref v) = *lval {
- self.locals.insert(v.index());
- }
- self.super_lvalue(lval, ctx, loc);
}
}
});
self.super_basic_block_data(block, data);
}
- fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
- match *lval {
- Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]),
- _ => (),
- };
- self.super_lvalue(lval, ctx, loc);
+ fn visit_local(&mut self, l: &mut Local, _: LvalueContext<'tcx>, _: Location) {
+ *l = Local::new(self.map[l.index()]);
}
}
//! Def-use analysis.
-use rustc::mir::{Local, Location, Lvalue, Mir};
+use rustc::mir::{Local, Location, Mir};
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
use rustc_data_structures::indexed_vec::IndexVec;
use std::marker::PhantomData;
}
fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
- where F: for<'a> FnMut(&'a mut Lvalue<'tcx>,
+ where F: for<'a> FnMut(&'a mut Local,
LvalueContext<'tcx>,
Location) {
for lvalue_use in &self.info[local].defs_and_uses {
pub fn replace_all_defs_and_uses_with(&self,
local: Local,
mir: &mut Mir<'tcx>,
- new_lvalue: Lvalue<'tcx>) {
- self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
+ new_local: Local) {
+ self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
}
}
info: IndexVec<Local, Info<'tcx>>,
}
-impl<'tcx> DefUseFinder<'tcx> {
- fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
- let info = &mut self.info;
-
- if let Lvalue::Local(local) = *lvalue {
- Some(&mut info[local])
- } else {
- None
- }
- }
-}
-
impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
- fn visit_lvalue(&mut self,
- lvalue: &Lvalue<'tcx>,
- context: LvalueContext<'tcx>,
- location: Location) {
- if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
- info.defs_and_uses.push(Use {
- context,
- location,
- })
- }
- self.super_lvalue(lvalue, context, location)
+ fn visit_local(&mut self,
+ &local: &Local,
+ context: LvalueContext<'tcx>,
+ location: Location) {
+ self.info[local].defs_and_uses.push(Use {
+ context,
+ location,
+ });
}
}
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
fn new(query: Local, callback: F, _: &Mir<'tcx>)
-> MutateUseVisitor<'tcx, F>
- where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
+ where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
MutateUseVisitor {
query,
callback,
}
impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
- where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
- fn visit_lvalue(&mut self,
- lvalue: &mut Lvalue<'tcx>,
+ where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
+ fn visit_local(&mut self,
+ local: &mut Local,
context: LvalueContext<'tcx>,
location: Location) {
- if let Lvalue::Local(local) = *lvalue {
- if local == self.query {
- (self.callback)(lvalue, context, location)
- }
+ if *local == self.query {
+ (self.callback)(local, context, location)
}
- self.super_lvalue(lvalue, context, location)
}
}
}
impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
- fn visit_lvalue(&mut self,
- lvalue: &Lvalue<'tcx>,
- context: LvalueContext<'tcx>,
- location: Location) {
- if let Lvalue::Local(local) = *lvalue {
- match context {
- LvalueContext::Store |
-
- // We let Call defined the result in both the success and unwind cases.
- // This may not be right.
- LvalueContext::Call |
-
- // Storage live and storage dead aren't proper defines, but we can ignore
- // values that come before them.
- LvalueContext::StorageLive |
- LvalueContext::StorageDead => {
- self.defs.add(&local);
- }
- LvalueContext::Projection(..) |
-
- // Borrows only consider their local used at the point of the borrow.
- // This won't affect the results since we use this analysis for generators
- // and we only care about the result at suspension points. Borrows cannot
- // cross suspension points so this behavior is unproblematic.
- LvalueContext::Borrow { .. } |
-
- LvalueContext::Inspect |
- LvalueContext::Consume |
- LvalueContext::Validate |
-
- // We consider drops to always be uses of locals.
- // Drop eloboration should be run before this analysis otherwise
- // the results might be too pessimistic.
- LvalueContext::Drop => {
- // Ignore uses which are already defined in this block
- if !self.pre_defs.contains(&local) {
- self.uses.add(&local);
- }
+ fn visit_local(&mut self,
+ &local: &Local,
+ context: LvalueContext<'tcx>,
+ _: Location) {
+ match context {
+ LvalueContext::Store |
+
+ // We let Call defined the result in both the success and unwind cases.
+ // This may not be right.
+ LvalueContext::Call |
+
+ // Storage live and storage dead aren't proper defines, but we can ignore
+ // values that come before them.
+ LvalueContext::StorageLive |
+ LvalueContext::StorageDead => {
+ self.defs.add(&local);
+ }
+ LvalueContext::Projection(..) |
+
+ // Borrows only consider their local used at the point of the borrow.
+ // This won't affect the results since we use this analysis for generators
+ // and we only care about the result at suspension points. Borrows cannot
+ // cross suspension points so this behavior is unproblematic.
+ LvalueContext::Borrow { .. } |
+
+ LvalueContext::Inspect |
+ LvalueContext::Consume |
+ LvalueContext::Validate |
+
+ // We consider drops to always be uses of locals.
+ // Drop eloboration should be run before this analysis otherwise
+ // the results might be too pessimistic.
+ LvalueContext::Drop => {
+ // Ignore uses which are already defined in this block
+ if !self.pre_defs.contains(&local) {
+ self.uses.add(&local);
}
}
}
-
- self.super_lvalue(lvalue, context, location)
}
}
location: Location) {
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
- // Allow uses of projections of immediate pair fields.
if let mir::Lvalue::Projection(ref proj) = *lvalue {
- if let mir::Lvalue::Local(_) = proj.base {
- let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
-
- let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
- if common::type_is_imm_pair(self.cx.ccx, ty) {
+ // Allow uses of projections of immediate pair fields.
+ if let LvalueContext::Consume = context {
+ if let mir::Lvalue::Local(_) = proj.base {
if let mir::ProjectionElem::Field(..) = proj.elem {
- if let LvalueContext::Consume = context {
+ let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
+
+ let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+ if common::type_is_imm_pair(self.cx.ccx, ty) {
return;
}
}
}
}
- }
- if let mir::Lvalue::Local(index) = *lvalue {
- match context {
- LvalueContext::Call => {
- self.mark_assigned(index);
- }
+ // A deref projection only reads the pointer, never needs the lvalue.
+ if let mir::ProjectionElem::Deref = proj.elem {
+ return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+ }
+ }
- LvalueContext::StorageLive |
- LvalueContext::StorageDead |
- LvalueContext::Validate |
- LvalueContext::Inspect |
- LvalueContext::Consume => {}
+ self.super_lvalue(lvalue, context, location);
+ }
- LvalueContext::Store |
- LvalueContext::Borrow { .. } |
- LvalueContext::Projection(..) => {
- self.mark_as_lvalue(index);
- }
+ fn visit_local(&mut self,
+ &index: &mir::Local,
+ context: LvalueContext<'tcx>,
+ _: Location) {
+ match context {
+ LvalueContext::Call => {
+ self.mark_assigned(index);
+ }
- LvalueContext::Drop => {
- let ty = lvalue.ty(self.cx.mir, self.cx.ccx.tcx());
- let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+ LvalueContext::StorageLive |
+ LvalueContext::StorageDead |
+ LvalueContext::Validate |
+ LvalueContext::Inspect |
+ LvalueContext::Consume => {}
- // Only need the lvalue if we're actually dropping it.
- if self.cx.ccx.shared().type_needs_drop(ty) {
- self.mark_as_lvalue(index);
- }
- }
+ LvalueContext::Store |
+ LvalueContext::Borrow { .. } |
+ LvalueContext::Projection(..) => {
+ self.mark_as_lvalue(index);
}
- }
- // A deref projection only reads the pointer, never needs the lvalue.
- if let mir::Lvalue::Projection(ref proj) = *lvalue {
- if let mir::ProjectionElem::Deref = proj.elem {
- return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
+ LvalueContext::Drop => {
+ let ty = mir::Lvalue::Local(index).ty(self.cx.mir, self.cx.ccx.tcx());
+ let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
+
+ // Only need the lvalue if we're actually dropping it.
+ if self.cx.ccx.shared().type_needs_drop(ty) {
+ self.mark_as_lvalue(index);
+ }
}
}
-
- self.super_lvalue(lvalue, context, location);
}
}