diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index edc7922f46eec..0a6a6edf44816 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -158,22 +158,7 @@ macro_rules! make_mir_visitor { self.super_place_base(base, context, location); } - fn visit_projection(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, - projection: & $($mutability)? [PlaceElem<'tcx>], - context: PlaceContext, - location: Location) { - self.super_projection(base, projection, context, location); - } - - fn visit_projection_elem(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, - proj_base: & $($mutability)? [PlaceElem<'tcx>], - elem: & $($mutability)? PlaceElem<'tcx>, - context: PlaceContext, - location: Location) { - self.super_projection_elem(base, proj_base, elem, context, location); - } + visit_place_fns!($($mutability)?); fn visit_constant(&mut self, constant: & $($mutability)? Constant<'tcx>, @@ -681,28 +666,6 @@ macro_rules! make_mir_visitor { ); } - fn super_place(&mut self, - place: & $($mutability)? Place<'tcx>, - context: PlaceContext, - location: Location) { - let mut context = context; - - if !place.projection.is_empty() { - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - } - - self.visit_place_base(& $($mutability)? place.base, context, location); - - self.visit_projection(& $($mutability)? place.base, - & $($mutability)? place.projection, - context, - location); - } - fn super_place_base(&mut self, place_base: & $($mutability)? PlaceBase<'tcx>, context: PlaceContext, @@ -717,45 +680,6 @@ macro_rules! make_mir_visitor { } } - fn super_projection(&mut self, - base: & $($mutability)? PlaceBase<'tcx>, - projection: & $($mutability)? [PlaceElem<'tcx>], - context: PlaceContext, - location: Location) { - let mut cursor = projection; - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - self.visit_projection_elem(base, cursor, elem, context, location); - } - } - - fn super_projection_elem(&mut self, - _base: & $($mutability)? PlaceBase<'tcx>, - _proj_base: & $($mutability)? [PlaceElem<'tcx>], - elem: & $($mutability)? PlaceElem<'tcx>, - _context: PlaceContext, - location: Location) { - match elem { - ProjectionElem::Field(_field, ty) => { - self.visit_ty(ty, TyContext::Location(location)); - } - ProjectionElem::Index(local) => { - self.visit_local( - local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); - } - ProjectionElem::Deref | - ProjectionElem::Subslice { from: _, to: _ } | - ProjectionElem::ConstantIndex { offset: _, - min_length: _, - from_end: _ } | - ProjectionElem::Downcast(_, _) => { - } - } - } - fn super_local_decl(&mut self, local: Local, local_decl: & $($mutability)? LocalDecl<'tcx>) { @@ -858,6 +782,141 @@ macro_rules! make_mir_visitor { } } +macro_rules! visit_place_fns { + (mut) => ( + fn super_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.visit_place_base(&mut place.base, context, location); + + if let Some(new_projection) = self.process_projection(&place.projection) { + place.projection = new_projection; + } + } + + fn process_projection( + &mut self, + projection: &'a [PlaceElem<'tcx>], + ) -> Option]>> { + let mut projection = Cow::Borrowed(projection); + + for i in 0..projection.len() { + if let Some(elem) = projection.get(i) { + if let Cow::Owned(elem) = self.process_projection_elem(Cow::Borrowed(elem)) { + let vec = projection.to_mut(); + vec[i] = elem; + } + } + } + + match projection { + Cow::Borrowed(_) => None, + Cow::Owned(vec) => Some(vec.into_boxed_slice()), + } + } + + fn process_projection_elem( + &mut self, + elem: Cow<'a, PlaceElem<'tcx>>, + ) -> Cow<'a, PlaceElem<'tcx>> { + elem + } + ); + + () => ( + fn visit_projection( + &mut self, + base: &PlaceBase<'tcx>, + projection: &[PlaceElem<'tcx>], + context: PlaceContext, + location: Location, + ) { + self.super_projection(base, projection, context, location); + } + + fn visit_projection_elem( + &mut self, + base: &PlaceBase<'tcx>, + proj_base: &[PlaceElem<'tcx>], + elem: &PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + self.super_projection_elem(base, proj_base, elem, context, location); + } + + fn super_place( + &mut self, + place: &Place<'tcx>, + context: PlaceContext, + location: Location, + ) { + let mut context = context; + + if !place.projection.is_empty() { + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + } + + self.visit_place_base(&place.base, context, location); + + self.visit_projection(&place.base, + &place.projection, + context, + location); + } + + fn super_projection( + &mut self, + base: &PlaceBase<'tcx>, + projection: &[PlaceElem<'tcx>], + context: PlaceContext, + location: Location, + ) { + let mut cursor = projection; + while let [proj_base @ .., elem] = cursor { + cursor = proj_base; + self.visit_projection_elem(base, cursor, elem, context, location); + } + } + + fn super_projection_elem( + &mut self, + _base: &PlaceBase<'tcx>, + _proj_base: &[PlaceElem<'tcx>], + elem: &PlaceElem<'tcx>, + _context: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Field(_field, ty) => { + self.visit_ty(ty, TyContext::Location(location)); + } + ProjectionElem::Index(local) => { + self.visit_local( + local, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location + ); + } + ProjectionElem::Deref | + ProjectionElem::Subslice { from: _, to: _ } | + ProjectionElem::ConstantIndex { offset: _, + min_length: _, + from_end: _ } | + ProjectionElem::Downcast(_, _) => { + } + } + } + ); +} + make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 88ad1fb129509..0073443817003 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,9 +1,10 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::mir::{Location, Body, Promoted}; +use rustc::mir::{Body, Location, PlaceElem, Promoted}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc_index::vec::IndexVec; +use std::borrow::Cow; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. @@ -62,6 +63,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { debug!("visit_ty: ty={:?}", ty); } + fn process_projection_elem( + &mut self, + elem: Cow<'b, PlaceElem<'tcx>>, + ) -> Cow<'b, PlaceElem<'tcx>> { + match elem { + Cow::Borrowed(PlaceElem::Field(field, ty)) => { + Cow::Owned(PlaceElem::Field(*field, self.renumber_regions(ty))) + } + _ => elem, + } + } + fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { debug!("visit_substs(substs={:?}, location={:?})", substs, location); diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 38a04ce8f3815..3ed87fccd7be8 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -9,6 +9,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::*; use rustc::mir::visit::{MutVisitor, TyContext}; use crate::transform::{MirPass, MirSource}; +use std::borrow::Cow; struct EraseRegionsVisitor<'tcx> { tcx: TyCtxt<'tcx>, @@ -25,7 +26,6 @@ impl EraseRegionsVisitor<'tcx> { impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { *ty = self.tcx.erase_regions(ty); - self.super_ty(ty); } fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) { @@ -39,6 +39,18 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) { *substs = self.tcx.erase_regions(substs); } + + fn process_projection_elem( + &mut self, + elem: Cow<'a, PlaceElem<'tcx>>, + ) -> Cow<'a, PlaceElem<'tcx>> { + match elem { + Cow::Borrowed(PlaceElem::Field(field, ty)) => { + Cow::Owned(PlaceElem::Field(*field, self.tcx.erase_regions(ty))) + } + _ => elem, + } + } } pub struct EraseRegions; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 865fa012c2995..a801548efab08 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -88,6 +88,24 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { *local = self.to; } } + + fn visit_place(&mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location) { + self.visit_place_base(&mut place.base, context, location); + + let new_projection: Vec<_> = place.projection.iter().map(|elem| + match elem { + PlaceElem::Index(local) if *local == self.from => { + PlaceElem::Index(self.to) + } + _ => elem.clone(), + } + ).collect(); + + place.projection = new_projection.into_boxed_slice(); + } } struct DerefArgVisitor; @@ -110,7 +128,13 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { projection: Box::new([ProjectionElem::Deref]), }); } else { - self.super_place(place, context, location); + self.visit_place_base(&mut place.base, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(*local, self_arg()); + } + } } } } @@ -137,7 +161,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]), }); } else { - self.super_place(place, context, location); + self.visit_place_base(&mut place.base, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(*local, self_arg()); + } + } } } } @@ -247,17 +277,25 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { assert_eq!(self.remap.get(local), None); } - fn visit_place(&mut self, - place: &mut Place<'tcx>, - context: PlaceContext, - location: Location) { + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { if let PlaceBase::Local(l) = place.base { // Replace an Local in the remap with a generator struct access if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) { replace_base(place, self.make_field(variant_index, idx, ty)); } } else { - self.super_place(place, context, location); + self.visit_place_base(&mut place.base, context, location); + + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(*local, self_arg()); + } + } } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 9830ed35ffc3e..6a02985c8c260 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -11,6 +11,7 @@ use rustc::mir::visit::*; use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc::ty::subst::{Subst, SubstsRef}; +use std::borrow::Cow; use std::collections::VecDeque; use std::iter; use crate::transform::{MirPass, MirSource}; @@ -647,38 +648,45 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { debug!("updating target `{:?}`, new: `{:?}`", tgt, new); new } -} -impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { - fn visit_local(&mut self, - local: &mut Local, - _ctxt: PlaceContext, - _location: Location) { + fn make_integrate_local(&self, local: &Local) -> Local { if *local == RETURN_PLACE { match self.destination { Place { base: PlaceBase::Local(l), projection: box [], } => { - *local = l; - return; + return l; }, ref place => bug!("Return place is {:?}, not local", place) } } + let idx = local.index() - 1; if idx < self.args.len() { - *local = self.args[idx]; - return; + return self.args[idx]; } - *local = self.local_map[Local::new(idx - self.args.len())]; + + self.local_map[Local::new(idx - self.args.len())] } +} - fn visit_place(&mut self, - place: &mut Place<'tcx>, - _ctxt: PlaceContext, - _location: Location) { +impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn visit_local( + &mut self, + local: &mut Local, + _ctxt: PlaceContext, + _location: Location, + ) { + *local = self.make_integrate_local(local); + } + fn visit_place( + &mut self, + place: &mut Place<'tcx>, + context: PlaceContext, + location: Location, + ) { match place { Place { base: PlaceBase::Local(RETURN_PLACE), @@ -687,7 +695,21 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { // Return pointer; update the place itself *place = self.destination.clone(); }, - _ => self.super_place(place, _ctxt, _location) + _ => { + self.super_place(place, context, location); + } + } + } + + fn process_projection_elem( + &mut self, + elem: Cow<'b, PlaceElem<'tcx>>, + ) -> Cow<'b, PlaceElem<'tcx>> { + match elem { + Cow::Borrowed(PlaceElem::Index(local)) => { + Cow::Owned(PlaceElem::Index(self.make_integrate_local(local))) + } + _ => elem, } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 5d241ffe1c06a..7b348b054175e 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -23,6 +23,7 @@ use syntax_pos::Span; use rustc_index::vec::{IndexVec, Idx}; use std::{iter, mem, usize}; +use std::borrow::Cow; /// State of a temporary during collection and promotion. #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -191,6 +192,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }); } + fn is_temp_kind(&self, local: Local) -> bool { + self.source.local_kind(local) == LocalKind::Temp + } + /// Copies the initialization of this temp to the /// promoted MIR, recursing through temps. fn promote_temp(&mut self, temp: Local) -> Local { @@ -396,10 +401,22 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { local: &mut Local, _: PlaceContext, _: Location) { - if self.source.local_kind(*local) == LocalKind::Temp { + if self.is_temp_kind(*local) { *local = self.promote_temp(*local); } } + + fn process_projection_elem( + &mut self, + elem: Cow<'b, PlaceElem<'tcx>>, + ) -> Cow<'b, PlaceElem<'tcx>> { + match elem { + Cow::Borrowed(PlaceElem::Index(local)) if self.is_temp_kind(*local) => { + Cow::Owned(PlaceElem::Index(self.promote_temp(*local))) + } + _ => elem, + } + } } pub fn promote_candidates<'tcx>( diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 9ffff9a92fa53..b0199fe807d35 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -366,7 +366,20 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { }); self.super_basic_block_data(block, data); } + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } + + fn process_projection_elem( + &mut self, + elem: Cow<'a, PlaceElem<'tcx>>, + ) -> Cow<'a, PlaceElem<'tcx>> { + match elem { + Cow::Borrowed(PlaceElem::Index(local)) => { + Cow::Owned(PlaceElem::Index(self.map[*local].unwrap())) + } + _ => elem, + } + } } diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 3aea25fa8769f..b7f89681e4d45 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -1,8 +1,9 @@ //! Def-use analysis. -use rustc::mir::{Local, Location, Body}; +use rustc::mir::{Body, Local, Location, PlaceElem}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; use rustc_index::vec::IndexVec; +use std::borrow::Cow; use std::mem; pub struct DefUseAnalysis { @@ -47,13 +48,10 @@ impl DefUseAnalysis { &self.info[local] } - fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, mut callback: F) - where F: for<'a> FnMut(&'a mut Local, - PlaceContext, - Location) { + fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) { for place_use in &self.info[local].defs_and_uses { MutateUseVisitor::new(local, - &mut callback, + new_local, body).visit_location(body, place_use.location) } } @@ -63,7 +61,7 @@ impl DefUseAnalysis { local: Local, body: &mut Body<'_>, new_local: Local) { - self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local) + self.mutate_defs_and_uses(local, body, new_local) } } @@ -117,30 +115,39 @@ impl Info { } } -struct MutateUseVisitor { +struct MutateUseVisitor { query: Local, - callback: F, + new_local: Local, } -impl MutateUseVisitor { - fn new(query: Local, callback: F, _: &Body<'_>) - -> MutateUseVisitor - where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) { +impl MutateUseVisitor { + fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor { MutateUseVisitor { query, - callback, + new_local, } } } -impl MutVisitor<'_> for MutateUseVisitor - where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) { +impl MutVisitor<'_> for MutateUseVisitor { fn visit_local(&mut self, local: &mut Local, - context: PlaceContext, - location: Location) { + _context: PlaceContext, + _location: Location) { if *local == self.query { - (self.callback)(local, context, location) + *local = self.new_local; + } + } + + fn process_projection_elem( + &mut self, + elem: Cow<'a, PlaceElem<'tcx>>, + ) -> Cow<'a, PlaceElem<'tcx>> { + match elem { + Cow::Borrowed(PlaceElem::Index(local)) if *local == self.query => { + Cow::Owned(PlaceElem::Index(self.new_local)) + } + _ => elem, } } }