mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
rustc_mir: implement visit_local instead/along visit_lvalue where possible.
This commit is contained in:
parent
2f2b8b34c2
commit
c911925243
@ -256,7 +256,9 @@ macro_rules! make_mir_visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local(&mut self,
|
fn visit_local(&mut self,
|
||||||
_local: & $($mutability)* Local) {
|
_local: & $($mutability)* Local,
|
||||||
|
_context: LvalueContext<'tcx>,
|
||||||
|
_location: Location) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_visibility_scope(&mut self,
|
fn visit_visibility_scope(&mut self,
|
||||||
@ -610,7 +612,7 @@ macro_rules! make_mir_visitor {
|
|||||||
location: Location) {
|
location: Location) {
|
||||||
match *lvalue {
|
match *lvalue {
|
||||||
Lvalue::Local(ref $($mutability)* local) => {
|
Lvalue::Local(ref $($mutability)* local) => {
|
||||||
self.visit_local(local);
|
self.visit_local(local, context, location);
|
||||||
}
|
}
|
||||||
Lvalue::Static(ref $($mutability)* static_) => {
|
Lvalue::Static(ref $($mutability)* static_) => {
|
||||||
self.visit_static(static_, context, location);
|
self.visit_static(static_, context, location);
|
||||||
|
@ -236,8 +236,7 @@ impl<'tcx> Action<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replace all uses of the destination local with the source local.
|
// 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_local);
|
||||||
def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
|
|
||||||
|
|
||||||
// Finally, zap the now-useless assignment instruction.
|
// Finally, zap the now-useless assignment instruction.
|
||||||
debug!(" Deleting assignment");
|
debug!(" Deleting assignment");
|
||||||
|
@ -88,7 +88,9 @@ struct RenameLocalVisitor {
|
|||||||
|
|
||||||
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
||||||
fn visit_local(&mut self,
|
fn visit_local(&mut self,
|
||||||
local: &mut Local) {
|
local: &mut Local,
|
||||||
|
_: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
if *local == self.from {
|
if *local == self.from {
|
||||||
*local = self.to;
|
*local = self.to;
|
||||||
}
|
}
|
||||||
@ -98,6 +100,13 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
|||||||
struct DerefArgVisitor;
|
struct DerefArgVisitor;
|
||||||
|
|
||||||
impl<'tcx> MutVisitor<'tcx> for 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,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
lvalue: &mut Lvalue<'tcx>,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
@ -177,6 +186,13 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, '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,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
lvalue: &mut Lvalue<'tcx>,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
|
@ -589,16 +589,6 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||||||
new
|
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> {
|
fn arg_index(&self, arg: Local) -> Option<usize> {
|
||||||
let idx = arg.index();
|
let idx = arg.index();
|
||||||
if idx > 0 && idx <= self.args.len() {
|
if idx > 0 && idx <= self.args.len() {
|
||||||
@ -610,32 +600,35 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
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,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
lvalue: &mut Lvalue<'tcx>,
|
||||||
_ctxt: LvalueContext<'tcx>,
|
_ctxt: LvalueContext<'tcx>,
|
||||||
_location: Location) {
|
_location: Location) {
|
||||||
if let Lvalue::Local(ref mut local) = *lvalue {
|
if let Lvalue::Local(RETURN_POINTER) = *lvalue {
|
||||||
if let Some(l) = self.update_local(*local) {
|
// Return pointer; update the lvalue itself
|
||||||
// Temp or Var; update the local reference
|
*lvalue = self.destination.clone();
|
||||||
*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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.super_lvalue(lvalue, _ctxt, _location)
|
self.super_lvalue(lvalue, _ctxt, _location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,52 +83,49 @@ struct TempCollector<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
&index: &Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
self.super_lvalue(lvalue, context, location);
|
// We're only interested in temporaries
|
||||||
if let Lvalue::Local(index) = *lvalue {
|
if self.mir.local_kind(index) != LocalKind::Temp {
|
||||||
// We're only interested in temporaries
|
return;
|
||||||
if self.mir.local_kind(index) != LocalKind::Temp {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore drops, if the temp gets promoted,
|
// Ignore drops, if the temp gets promoted,
|
||||||
// then it's constant and thus drop is noop.
|
// then it's constant and thus drop is noop.
|
||||||
// Storage live ranges are also irrelevant.
|
// Storage live ranges are also irrelevant.
|
||||||
if context.is_drop() || context.is_storage_marker() {
|
if context.is_drop() || context.is_storage_marker() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let temp = &mut self.temps[index];
|
let temp = &mut self.temps[index];
|
||||||
if *temp == TempState::Undefined {
|
if *temp == TempState::Undefined {
|
||||||
match context {
|
match context {
|
||||||
LvalueContext::Store |
|
LvalueContext::Store |
|
||||||
LvalueContext::Call => {
|
LvalueContext::Call => {
|
||||||
*temp = TempState::Defined {
|
*temp = TempState::Defined {
|
||||||
location,
|
location,
|
||||||
uses: 0
|
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;
|
|
||||||
return;
|
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) {
|
fn visit_source_info(&mut self, source_info: &SourceInfo) {
|
||||||
@ -326,16 +323,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||||||
|
|
||||||
/// Replaces all temporaries with their promoted counterparts.
|
/// Replaces all temporaries with their promoted counterparts.
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
local: &mut Local,
|
||||||
context: LvalueContext<'tcx>,
|
_: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
_: Location) {
|
||||||
if let Lvalue::Local(ref mut temp) = *lvalue {
|
if self.source.local_kind(*local) == LocalKind::Temp {
|
||||||
if self.source.local_kind(*temp) == LocalKind::Temp {
|
*local = self.promote_temp(*local);
|
||||||
*temp = self.promote_temp(*temp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.super_lvalue(lvalue, context, location);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,33 +499,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||||||
/// For functions (constant or not), it also records
|
/// For functions (constant or not), it also records
|
||||||
/// candidates for promotion in promotion_candidates.
|
/// candidates for promotion in promotion_candidates.
|
||||||
impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
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,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
lvalue: &Lvalue<'tcx>,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
match *lvalue {
|
match *lvalue {
|
||||||
Lvalue::Local(local) => match self.mir.local_kind(local) {
|
Lvalue::Local(ref local) => self.visit_local(local, context, location),
|
||||||
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::Static(ref global) => {
|
Lvalue::Static(ref global) => {
|
||||||
self.add(Qualif::STATIC);
|
self.add(Qualif::STATIC);
|
||||||
|
|
||||||
|
@ -352,15 +352,11 @@ struct DeclMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for DeclMarker {
|
impl<'tcx> Visitor<'tcx> for DeclMarker {
|
||||||
fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
|
fn visit_local(&mut self, local: &Local, ctx: LvalueContext<'tcx>, _: Location) {
|
||||||
if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead {
|
// ignore these altogether, they get removed along with their otherwise unused decls.
|
||||||
// ignore these altogether, they get removed along with their otherwise unused decls.
|
if ctx != LvalueContext::StorageLive && ctx != LvalueContext::StorageDead {
|
||||||
return;
|
self.locals.insert(local.index());
|
||||||
}
|
}
|
||||||
if let Lvalue::Local(ref v) = *lval {
|
|
||||||
self.locals.insert(v.index());
|
|
||||||
}
|
|
||||||
self.super_lvalue(lval, ctx, loc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,11 +380,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
|
|||||||
});
|
});
|
||||||
self.super_basic_block_data(block, data);
|
self.super_basic_block_data(block, data);
|
||||||
}
|
}
|
||||||
fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
|
fn visit_local(&mut self, l: &mut Local, _: LvalueContext<'tcx>, _: Location) {
|
||||||
match *lval {
|
*l = Local::new(self.map[l.index()]);
|
||||||
Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]),
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
self.super_lvalue(lval, ctx, loc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
//! Def-use analysis.
|
//! 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::mir::visit::{LvalueContext, MutVisitor, Visitor};
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@ -51,7 +51,7 @@ impl<'tcx> DefUseAnalysis<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
|
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>,
|
LvalueContext<'tcx>,
|
||||||
Location) {
|
Location) {
|
||||||
for lvalue_use in &self.info[local].defs_and_uses {
|
for lvalue_use in &self.info[local].defs_and_uses {
|
||||||
@ -65,8 +65,8 @@ impl<'tcx> DefUseAnalysis<'tcx> {
|
|||||||
pub fn replace_all_defs_and_uses_with(&self,
|
pub fn replace_all_defs_and_uses_with(&self,
|
||||||
local: Local,
|
local: Local,
|
||||||
mir: &mut Mir<'tcx>,
|
mir: &mut Mir<'tcx>,
|
||||||
new_lvalue: Lvalue<'tcx>) {
|
new_local: Local) {
|
||||||
self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
|
self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,30 +74,15 @@ struct DefUseFinder<'tcx> {
|
|||||||
info: IndexVec<Local, Info<'tcx>>,
|
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> {
|
impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
&local: &Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
|
self.info[local].defs_and_uses.push(Use {
|
||||||
info.defs_and_uses.push(Use {
|
context,
|
||||||
context,
|
location,
|
||||||
location,
|
});
|
||||||
})
|
|
||||||
}
|
|
||||||
self.super_lvalue(lvalue, context, location)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +119,7 @@ struct MutateUseVisitor<'tcx, F> {
|
|||||||
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
||||||
fn new(query: Local, callback: F, _: &Mir<'tcx>)
|
fn new(query: Local, callback: F, _: &Mir<'tcx>)
|
||||||
-> MutateUseVisitor<'tcx, F>
|
-> 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 {
|
MutateUseVisitor {
|
||||||
query,
|
query,
|
||||||
callback,
|
callback,
|
||||||
@ -144,16 +129,13 @@ impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
|
impl<'tcx, F> MutVisitor<'tcx> for 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) {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
local: &mut Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Lvalue::Local(local) = *lvalue {
|
if *local == self.query {
|
||||||
if local == self.query {
|
(self.callback)(local, context, location)
|
||||||
(self.callback)(lvalue, context, location)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.super_lvalue(lvalue, context, location)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,49 +60,45 @@ struct BlockInfoVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
|
impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
&local: &Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
_: Location) {
|
||||||
if let Lvalue::Local(local) = *lvalue {
|
match context {
|
||||||
match context {
|
LvalueContext::Store |
|
||||||
LvalueContext::Store |
|
|
||||||
|
|
||||||
// We let Call defined the result in both the success and unwind cases.
|
// We let Call defined the result in both the success and unwind cases.
|
||||||
// This may not be right.
|
// This may not be right.
|
||||||
LvalueContext::Call |
|
LvalueContext::Call |
|
||||||
|
|
||||||
// Storage live and storage dead aren't proper defines, but we can ignore
|
// Storage live and storage dead aren't proper defines, but we can ignore
|
||||||
// values that come before them.
|
// values that come before them.
|
||||||
LvalueContext::StorageLive |
|
LvalueContext::StorageLive |
|
||||||
LvalueContext::StorageDead => {
|
LvalueContext::StorageDead => {
|
||||||
self.defs.add(&local);
|
self.defs.add(&local);
|
||||||
}
|
}
|
||||||
LvalueContext::Projection(..) |
|
LvalueContext::Projection(..) |
|
||||||
|
|
||||||
// Borrows only consider their local used at the point of the borrow.
|
// 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
|
// 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
|
// and we only care about the result at suspension points. Borrows cannot
|
||||||
// cross suspension points so this behavior is unproblematic.
|
// cross suspension points so this behavior is unproblematic.
|
||||||
LvalueContext::Borrow { .. } |
|
LvalueContext::Borrow { .. } |
|
||||||
|
|
||||||
LvalueContext::Inspect |
|
LvalueContext::Inspect |
|
||||||
LvalueContext::Consume |
|
LvalueContext::Consume |
|
||||||
LvalueContext::Validate |
|
LvalueContext::Validate |
|
||||||
|
|
||||||
// We consider drops to always be uses of locals.
|
// We consider drops to always be uses of locals.
|
||||||
// Drop eloboration should be run before this analysis otherwise
|
// Drop eloboration should be run before this analysis otherwise
|
||||||
// the results might be too pessimistic.
|
// the results might be too pessimistic.
|
||||||
LvalueContext::Drop => {
|
LvalueContext::Drop => {
|
||||||
// Ignore uses which are already defined in this block
|
// Ignore uses which are already defined in this block
|
||||||
if !self.pre_defs.contains(&local) {
|
if !self.pre_defs.contains(&local) {
|
||||||
self.uses.add(&local);
|
self.uses.add(&local);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.super_lvalue(lvalue, context, location)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,54 +134,22 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||||||
location: Location) {
|
location: Location) {
|
||||||
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
|
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::Projection(ref proj) = *lvalue {
|
||||||
if let mir::Lvalue::Local(_) = proj.base {
|
// Allow uses of projections of immediate pair fields.
|
||||||
let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
|
if let LvalueContext::Consume = context {
|
||||||
|
if let mir::Lvalue::Local(_) = proj.base {
|
||||||
let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
|
|
||||||
if common::type_is_imm_pair(self.cx.ccx, ty) {
|
|
||||||
if let mir::ProjectionElem::Field(..) = proj.elem {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let mir::Lvalue::Local(index) = *lvalue {
|
// A deref projection only reads the pointer, never needs the lvalue.
|
||||||
match context {
|
|
||||||
LvalueContext::Call => {
|
|
||||||
self.mark_assigned(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
LvalueContext::StorageLive |
|
|
||||||
LvalueContext::StorageDead |
|
|
||||||
LvalueContext::Validate |
|
|
||||||
LvalueContext::Inspect |
|
|
||||||
LvalueContext::Consume => {}
|
|
||||||
|
|
||||||
LvalueContext::Store |
|
|
||||||
LvalueContext::Borrow { .. } |
|
|
||||||
LvalueContext::Projection(..) => {
|
|
||||||
self.mark_as_lvalue(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()));
|
|
||||||
|
|
||||||
// Only need the lvalue if we're actually dropping it.
|
|
||||||
if self.cx.ccx.shared().type_needs_drop(ty) {
|
|
||||||
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 {
|
if let mir::ProjectionElem::Deref = proj.elem {
|
||||||
return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
||||||
}
|
}
|
||||||
@ -189,6 +157,39 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||||||
|
|
||||||
self.super_lvalue(lvalue, context, location);
|
self.super_lvalue(lvalue, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_local(&mut self,
|
||||||
|
&index: &mir::Local,
|
||||||
|
context: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
|
match context {
|
||||||
|
LvalueContext::Call => {
|
||||||
|
self.mark_assigned(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
LvalueContext::StorageLive |
|
||||||
|
LvalueContext::StorageDead |
|
||||||
|
LvalueContext::Validate |
|
||||||
|
LvalueContext::Inspect |
|
||||||
|
LvalueContext::Consume => {}
|
||||||
|
|
||||||
|
LvalueContext::Store |
|
||||||
|
LvalueContext::Borrow { .. } |
|
||||||
|
LvalueContext::Projection(..) => {
|
||||||
|
self.mark_as_lvalue(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
Loading…
Reference in New Issue
Block a user