From 96b641ae48cea1b9564d75b4d5d52a87523c43e7 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 14 Sep 2018 15:39:08 +0800 Subject: [PATCH 01/34] introduce new place definition --- src/librustc/mir/mod.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f824ab7e5b395..6e0dbdf5766ab 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -27,6 +27,7 @@ use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::List; use ty::subst::{Subst, Substs}; use ty::layout::VariantIdx; use ty::{ @@ -1887,6 +1888,7 @@ impl<'tcx> Debug for Statement<'tcx> { /////////////////////////////////////////////////////////////////////////// // Places +/// TODO(csmoe): merge the old Place repr into NeoPlace /// A path to a value; something that can be evaluated without /// changing or disturbing program state. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] @@ -1904,6 +1906,27 @@ pub enum Place<'tcx> { Projection(Box>), } +/// A new Place repr +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct NeoPlace<'tcx> { + base: PlaceBase<'tcx>, + elems: &'tcx List>, +} + +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List> {} + +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum PlaceBase<'tcx> { + /// local variable + Local(Local), + + /// static or static mut variable + Static(Box>), + + /// Constant code promoted to an injected static + Promoted(Box<(Promoted, Ty<'tcx>)>), +} + /// The def-id of a static, along with its normalized type (which is /// stored to avoid requiring normalization when reading MIR). #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] From 93c5ebb81a681af50d8647eea6f770d5a9fe78e2 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Tue, 25 Sep 2018 21:31:22 +0800 Subject: [PATCH 02/34] convert old Place to NeoPlace --- src/librustc/mir/mod.rs | 114 ++++++++++++++++++++++++++++++++++++- src/librustc/ty/context.rs | 27 ++++++++- 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 6e0dbdf5766ab..a10472d77797a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1907,7 +1907,7 @@ pub enum Place<'tcx> { } /// A new Place repr -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct NeoPlace<'tcx> { base: PlaceBase<'tcx>, elems: &'tcx List>, @@ -1915,6 +1915,39 @@ pub struct NeoPlace<'tcx> { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List> {} +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + pub fn as_new_place(self, place: &Place<'tcx>) -> NeoPlace<'tcx> { + let mut elems: Vec> = Vec::new(); + let mut p = place; + + while let Place::Projection(proj) = p { + elems.push(proj.elem); + p = &proj.base; + } + + elems.reverse(); + + match p.clone() { + Place::Projection(_) => unreachable!(), + + Place::Local(local) => NeoPlace { + base: PlaceBase::Local(local), + elems: self.mk_place_elems(elems.iter()), + }, + + Place::Static(static_) => NeoPlace { + base: PlaceBase::Static(static_), + elems: self.mk_place_elems(elems.iter()), + }, + + Place::Promoted(promoted) => NeoPlace { + base: PlaceBase::Promoted(promoted), + elems: self.mk_place_elems(elems.iter()), + }, + } + } +} + #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum PlaceBase<'tcx> { /// local variable @@ -1950,7 +1983,7 @@ pub struct Projection<'tcx, B, V, T> { pub elem: ProjectionElem<'tcx, V, T>, } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum ProjectionElem<'tcx, V, T> { Deref, Field(Field, T), @@ -2103,6 +2136,23 @@ impl<'tcx> Debug for Place<'tcx> { } } +impl<'tcx> Debug for PlaceBase<'tcx> { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + use self::PlaceBase::*; + + match self { + Local(id) => write!(fmt, "{:?}", *id), + Static(box self::Static { def_id, ty }) => write!( + fmt, + "({}: {:?})", + ty::tls::with(|tcx| tcx.item_path_str(*def_id)), + ty + ), + Promoted(promoted) => write!(fmt, "({:?}: {:?})", promoted.0, promoted.1), + } + } +} + /////////////////////////////////////////////////////////////////////////// // Scopes @@ -3324,6 +3374,41 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for NeoPlace<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + NeoPlace { + base: self.base.fold_with(folder), + elems: self.elems.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.base.visit_with(visitor) || + self.elems.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + self.clone() + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for &'tcx List> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); + folder.tcx().intern_place_elems(&v) + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + self.iter().any(|p| p.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { use mir::Rvalue::*; @@ -3444,6 +3529,31 @@ where } } +impl<'tcx, V, T> TypeFoldable<'tcx> for ProjectionElem<'tcx, V, T> +where + V: TypeFoldable<'tcx>, + T: TypeFoldable<'tcx>, +{ + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use self::ProjectionElem::*; + match self { + Deref => Deref, + Field(f, ty) => Field(*f, ty.fold_with(folder)), + Index(v) => Index(v.fold_with(folder)), + elem => elem.clone(), + } + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + use self::ProjectionElem::*; + match self { + Field(_, ty) => ty.visit_with(visitor), + Index(v) => v.visit_with(visitor), + _ => false, + } + } +} + impl<'tcx> TypeFoldable<'tcx> for Field { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { *self diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 4c8f81411163c..6edcac46bc5e8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -21,7 +21,7 @@ use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; -use mir::{self, Mir, interpret, ProjectionKind}; +use mir::{self, Mir, interpret, ProjectionKind, PlaceElem}; use mir::interpret::Allocation; use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; @@ -123,6 +123,7 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind>, existential_predicates: InternedSet<'tcx, List>>, predicates: InternedSet<'tcx, List>>, + place_elems: InternedSet<'tcx, List>>, clauses: InternedSet<'tcx, List>>, goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List>>, @@ -140,6 +141,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicates: Default::default(), + place_elems: Default::default(), clauses: Default::default(), goal: Default::default(), goal_list: Default::default(), @@ -1794,6 +1796,7 @@ nop_list_lift!{Clause<'a> => Clause<'tcx>} nop_list_lift!{Ty<'a> => Ty<'tcx>} nop_list_lift!{ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} nop_list_lift!{Predicate<'a> => Predicate<'tcx>} +nop_list_lift!{PlaceElem<'a> => PlaceElem<'tcx>} nop_list_lift!{CanonicalVarInfo => CanonicalVarInfo} nop_list_lift!{ProjectionKind<'a> => ProjectionKind<'tcx>} @@ -2279,6 +2282,13 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]> } } +impl<'tcx: 'lcx, 'lcx> Borrow<[PlaceElem<'lcx>]> + for Interned<'tcx, List>> { + fn borrow<'a>(&'a self) -> &'a [PlaceElem<'lcx>] { + &self.0[..] + } +} + impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, Const<'tcx>> { fn borrow<'a>(&'a self) -> &'a Const<'lcx> { &self.0 @@ -2387,6 +2397,7 @@ macro_rules! slice_interners { slice_interners!( existential_predicates: _intern_existential_predicates(ExistentialPredicate), predicates: _intern_predicates(Predicate), + place_elems: _intern_place_elems(PlaceElem), type_list: _intern_type_list(Ty), substs: _intern_substs(Kind), clauses: _intern_clauses(Clause), @@ -2711,6 +2722,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn intern_place_elems(self, place_elems: &[PlaceElem<'tcx>]) + -> &'tcx List> { + if place_elems.is_empty() { + List::empty() + } else { + self._intern_place_elems(place_elems) + } + } + pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List> { if ts.len() == 0 { List::empty() @@ -2787,6 +2807,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { iter.intern_with(|xs| self.intern_predicates(xs)) } + pub fn mk_place_elems], + &'tcx List>>>(self, iter: I) -> I::Output { + iter.intern_with(|xs| self.intern_place_elems(xs)) + } + pub fn mk_type_list], &'tcx List>>>(self, iter: I) -> I::Output { iter.intern_with(|xs| self.intern_type_list(xs)) From 879f7c168d75aa026599a9190558c8e4ac5db24f Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 21 Sep 2018 21:17:48 +0800 Subject: [PATCH 03/34] rewrite methods with NeoPlace in mir/tcx --- src/librustc/mir/tcx.rs | 176 +++++++++++++++--- .../borrow_check/error_reporting.rs | 7 +- src/librustc_mir/borrow_check/mod.rs | 13 +- src/librustc_mir/borrow_check/move_errors.rs | 7 +- .../borrow_check/mutability_errors.rs | 7 +- 5 files changed, 174 insertions(+), 36 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 649370059f0ea..17505db3945d3 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -25,11 +25,13 @@ static_assert!(PLACE_TY_IS_3_PTRS_LARGE: mem::size_of::>() <= 24 ); -impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { - pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { +impl From> for PlaceTy<'tcx> { + fn from(ty: Ty<'tcx>) -> Self { PlaceTy::Ty { ty } } +} +impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match *self { PlaceTy::Ty { ty } => @@ -168,38 +170,162 @@ impl<'tcx> Place<'tcx> { } } + // If this is a field projection, and the field is being projected from a closure type, + // then returns the index of the field being projected. Note that this closure will always + // be `self` in the current MIR, because that is the only time we directly access the fields + // of a closure type. + //pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, + // tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { + // let (place, by_ref) = if let Place::Projection(ref proj) = self { + // if let ProjectionElem::Deref = proj.elem { + // (&proj.base, true) + // } else { + // (self, false) + // } + // } else { + // (self, false) + // }; + + // match place { + // Place::Projection(ref proj) => match proj.elem { + // ProjectionElem::Field(field, _ty) => { + // let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); + + // if (base_ty.is_closure() || base_ty.is_generator()) && + // (!by_ref || mir.upvar_decls[field.index()].by_ref) + // { + // Some(field) + // } else { + // None + // } + // }, + // _ => None, + // } + // _ => None, + // } + //} +} + +impl<'tcx> PlaceBase<'tcx> { + pub fn ty(&self, local_decls: &impl HasLocalDecls<'tcx>) -> Ty<'tcx> { + match self { + PlaceBase::Local(index) => local_decls.local_decls()[*index].ty, + PlaceBase::Promoted(data) => data.1, + PlaceBase::Static(data) => data.ty, + } + } +} + +impl<'tcx> NeoPlace<'tcx> { + pub fn ty<'a, 'gcx>( + &self, + local_decls: &impl HasLocalDecls<'tcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + ) -> PlaceTy<'tcx> { + // the PlaceTy is the *final* type with all projection applied + // if there is no projection, that just refers to `base`: + // + // Place: base.[a, b, c] + // ^-- projection + // ^-- PlaceTy + // + // Place: base.[] + // ^^-- no projection + // ^^^^-- PlaceTy + + let mut place_ty = PlaceTy::from(self.base.ty(local_decls)); + + // apply .projection_ty() to all elems but only returns the final one. + for elem in self.elems.iter() { + place_ty = place_ty.projection_ty(tcx, elem); + } + + place_ty + } + /// If this is a field projection, and the field is being projected from a closure type, /// then returns the index of the field being projected. Note that this closure will always /// be `self` in the current MIR, because that is the only time we directly access the fields /// of a closure type. - pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, - tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { - let (place, by_ref) = if let Place::Projection(ref proj) = self { - if let ProjectionElem::Deref = proj.elem { - (&proj.base, true) + pub fn is_upvar_field_projection<'cx, 'gcx>( + &self, + mir: &'cx Mir<'tcx>, + tcx: &TyCtxt<'cx, 'gcx, 'tcx>, + ) -> Option { + // Look for either *(Place.field) or Place.field, + // where P is a place with closure type, + // these sorts of places represent accesses to the closure's captured upvars. + + // unwrap inner place when Deref matched. + // *(closure.field) + // ^ ^^^^^ inner projection_elem + // |-- Deref + let (elems, by_ref) = + if let Some(ProjectionElem::Deref) = self.elems.last() { + (&self.elems[..self.elems.len()-1], true) + } else { + (&self.elems[..], false) + }; + let mut elems = elems.iter().rev(); + + // closure.field + // ^^^^^ + if let Some(ProjectionElem::Field(field, _ty)) = elems.next() { + let base_ty = self.base.ty_with_projections(mir, *tcx, elems.rev()); + if (base_ty.is_closure() || base_ty.is_generator()) && + (!by_ref || mir.upvar_decls[field.index()].by_ref) + { + Some(*field) } else { - (self, false) + None } } else { - (self, false) - }; + None + } + } - match place { - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _ty) => { - let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); - - if (base_ty.is_closure() || base_ty.is_generator()) && - (!by_ref || mir.upvar_decls[field.index()].by_ref) - { - Some(field) - } else { - None - } + // for Place: + // (Base.[a, b, c]) + // ^^^^^^^^^^ ^-- projection + // |-- base_place + // + // Base.[] + // ^^^^ ^^-- no projection(empty) + // |-- base_place + pub fn split_projection<'cx, 'gcx>( + &self, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + ) -> (NeoPlace<'tcx>, Option<&'tcx PlaceElem<'tcx>>) { + // split place_elems + // Base.[a, b, c] + // ^^^^ ^-- projection(projection lives in the last elem) + // |-- place_elems + match self.elems.split_last() { + Some((projection, place_elems)) => ( + NeoPlace { + base: self.clone().base, + elems: tcx.intern_place_elems(place_elems), }, - _ => None, - } - _ => None, + Some(projection), + ), + _ => (self.clone(), None) + } + } + + pub fn has_no_projection(&self) -> bool { + self.elems.is_empty() + } + + // for projection returns the base place; + // Base.[a, b, c] => Base.[a, b] + // ^-- projection + // if no projection returns the place itself, + // Base.[] => Base.[] + // ^^-- no projection + pub fn projection_base<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> NeoPlace<'tcx> { + match self.split_projection(tcx) { + (place, Some(_)) => place, + (_, None) => self.clone(), } } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index b070031756798..b57594b35350e 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1598,8 +1598,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { + let neo_place = self.infcx.tcx.as_new_place(place); let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx); if let Some(field) = upvar_field_projection { let var_index = field.index(); let name = self.mir.upvar_decls[var_index].debug_name.to_string(); @@ -1659,9 +1660,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } ProjectionElem::Field(field, _ty) => { autoderef = true; - + let neo_place = self.infcx.tcx.as_new_place(place); let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx); if let Some(field) = upvar_field_projection { let var_index = field.index(); let name = self.mir.upvar_decls[var_index].debug_name.to_string(); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5597e4a6c597e..335b07513a566 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1235,7 +1235,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } Operand::Move(ref place @ Place::Projection(_)) | Operand::Copy(ref place @ Place::Projection(_)) => { - if let Some(field) = place.is_upvar_field_projection( + let neo_place = self.infcx.tcx.as_new_place(place); + if let Some(field) = neo_place.is_upvar_field_projection( self.mir, &self.infcx.tcx) { self.used_mut_upvars.push(field); } @@ -1965,7 +1966,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place: place @ Place::Projection(_), is_local_mutation_allowed: _, } => { - if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) { + let place = self.infcx.tcx.as_new_place(&place); + if let Some(field) = + place.is_upvar_field_projection(self.mir, &self.infcx.tcx) { self.used_mut_upvars.push(field); } } @@ -2038,7 +2041,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Mutably borrowed data is mutable, but only if we have a // unique path to the `&mut` hir::MutMutable => { - let mode = match place.is_upvar_field_projection( + let neo_place = self.infcx.tcx.as_new_place(place); + let mode = match neo_place.is_upvar_field_projection( self.mir, &self.infcx.tcx) { Some(field) @@ -2084,7 +2088,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..) => { - let upvar_field_projection = place.is_upvar_field_projection( + let neo_place = self.infcx.tcx.as_new_place(place); + let upvar_field_projection = neo_place.is_upvar_field_projection( self.mir, &self.infcx.tcx); if let Some(field) = upvar_field_projection { let decl = &self.mir.upvar_decls[field.index()]; diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 8539b5c26cee8..34d5065f2ff98 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -254,9 +254,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { }, }; let origin = Origin::Mir; + let neo_place = self.infcx.tcx.as_new_place(original_path); + let upvar_field_projection = + neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx); debug!("report: original_path={:?} span={:?}, kind={:?} \ original_path.is_upvar_field_projection={:?}", original_path, span, kind, - original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx)); + upvar_field_projection); ( match kind { IllegalMoveOriginKind::Static => { @@ -269,6 +272,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); let is_upvar_field_projection = self.prefixes(&original_path, PrefixSet::All) + .map(|p| self.infcx.tcx.as_new_place(&p)) .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) .is_some()); debug!("report: ty={:?}", ty); @@ -303,6 +307,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { span, place_description, origin); for prefix in self.prefixes(&original_path, PrefixSet::All) { + let prefix = self.infcx.tcx.as_new_place(prefix); if let Some(field) = prefix.is_upvar_field_projection( self.mir, &self.infcx.tcx) { let upvar_decl = &self.mir.upvar_decls[field.index()]; diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 4755c6daf0a77..fd41370ed4f88 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -66,7 +66,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { )); item_msg = format!("`{}`", access_place_desc.unwrap()); - if access_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() { + let neo_place = self.infcx.tcx.as_new_place(access_place); + if neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { let name = self.mir.upvar_decls[upvar_index.index()].debug_name; @@ -84,8 +85,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { debug_assert!(is_closure_or_generator( the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) )); - - reason = if access_place.is_upvar_field_projection(self.mir, + let neo_place = self.infcx.tcx.as_new_place(access_place); + reason = if neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() { ", as it is a captured variable in a `Fn` closure".to_string() } else { From e5abf2a0283750e3d285fb104a7f298dc24e8990 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sat, 22 Sep 2018 19:08:40 +0800 Subject: [PATCH 04/34] move from fixme to todo --- src/librustc/mir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a10472d77797a..780fe4189c7fd 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1888,7 +1888,7 @@ impl<'tcx> Debug for Statement<'tcx> { /////////////////////////////////////////////////////////////////////////// // Places -/// TODO(csmoe): merge the old Place repr into NeoPlace +/// FIXME(csmoe): merge the old Place repr into NeoPlace /// A path to a value; something that can be evaluated without /// changing or disturbing program state. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] From 0d715757df535f26b88120601326a198c814090f Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sat, 22 Sep 2018 19:51:49 +0800 Subject: [PATCH 05/34] impl mir visitor for NeoPlace --- src/librustc/mir/visit.rs | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 598303f29328f..ea07dee5be4c9 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -156,6 +156,15 @@ macro_rules! make_mir_visitor { self.super_place(place, context, location); } + fn visit_neoplace( + &mut self, + place: & $($mutability)* NeoPlace<'tcx>, + context: PlaceContext<'tcx>, + location: Location, + ) { + self.super_neoplace(place, context, location); + } + fn visit_static(&mut self, static_: & $($mutability)* Static<'tcx>, context: PlaceContext<'tcx>, @@ -752,6 +761,40 @@ macro_rules! make_mir_visitor { } } + fn super_neoplace( + &mut self, + place: & $($mutability)* NeoPlace<'tcx>, + context: PlaceContext<'tcx>, + location: Location, + ) { + let NeoPlace { + base, + elems, + } = place; + + match base { + PlaceBase::Local(local) => { + self.visit_local(local, context, location); + } + PlaceBase::Static(static_) => { + self.visit_static(static_, context, location); + } + PlaceBase::Promoted(promoted) => { + self.visit_ty(& $($mutability)* promoted.1, TyContext::Location(location)); + } + } + + if !elems.is_empty() { + for elem in elems.iter().cloned().rev() { + self.visit_projection_elem( + &$($mutability)* elem.clone(), + context, + location + ); + } + } + } + fn super_static(&mut self, static_: & $($mutability)* Static<'tcx>, _context: PlaceContext<'tcx>, From 576607645725df1f59214a019219370f3d1dd543 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sun, 23 Sep 2018 22:11:33 +0800 Subject: [PATCH 06/34] introduce NeoPlace in borrow_check/borrow_set --- src/librustc/mir/mod.rs | 4 ++-- src/librustc_mir/borrow_check/borrow_set.rs | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 780fe4189c7fd..acaaeb5a36481 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1909,8 +1909,8 @@ pub enum Place<'tcx> { /// A new Place repr #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct NeoPlace<'tcx> { - base: PlaceBase<'tcx>, - elems: &'tcx List>, + pub base: PlaceBase<'tcx>, + pub elems: &'tcx List>, } impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List> {} diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index ecbc6118bc37c..d650f6bd721f2 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -345,14 +345,16 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { // TEMP = &foo // // so extract `temp`. - let temp = if let &mir::Place::Local(temp) = assigned_place { - temp - } else { - span_bug!( - self.mir.source_info(start_location).span, - "expected 2-phase borrow to assign to a local, not `{:?}`", - assigned_place, - ); + let neo_place = self.tcx.as_new_place(assigned_place); + let temp = match neo_place.base { + mir::PlaceBase::Local(temp) if neo_place.has_no_projection() => temp, + _ => { + span_bug!( + self.mir.source_info(start_location).span, + "expected 2-phase borrow to assign to a local, not `{:?}`", + assigned_place, + ); + } }; // Consider the borrow not activated to start. When we find an activation, we'll update From 7b65fe836ec0312ca948cf70d74b4318185e43c3 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Tue, 25 Sep 2018 20:20:41 +0800 Subject: [PATCH 07/34] remove inefficient split_projection --- src/librustc/mir/tcx.rs | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 17505db3945d3..d55ca97a8dd6f 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -284,50 +284,9 @@ impl<'tcx> NeoPlace<'tcx> { } } - // for Place: - // (Base.[a, b, c]) - // ^^^^^^^^^^ ^-- projection - // |-- base_place - // - // Base.[] - // ^^^^ ^^-- no projection(empty) - // |-- base_place - pub fn split_projection<'cx, 'gcx>( - &self, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - ) -> (NeoPlace<'tcx>, Option<&'tcx PlaceElem<'tcx>>) { - // split place_elems - // Base.[a, b, c] - // ^^^^ ^-- projection(projection lives in the last elem) - // |-- place_elems - match self.elems.split_last() { - Some((projection, place_elems)) => ( - NeoPlace { - base: self.clone().base, - elems: tcx.intern_place_elems(place_elems), - }, - Some(projection), - ), - _ => (self.clone(), None) - } - } - pub fn has_no_projection(&self) -> bool { self.elems.is_empty() } - - // for projection returns the base place; - // Base.[a, b, c] => Base.[a, b] - // ^-- projection - // if no projection returns the place itself, - // Base.[] => Base.[] - // ^^-- no projection - pub fn projection_base<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> NeoPlace<'tcx> { - match self.split_projection(tcx) { - (place, Some(_)) => place, - (_, None) => self.clone(), - } - } } pub enum RvalueInitializationState { From f8a9a1f396501b2e1605b691b609fa0efa10ea06 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 26 Sep 2018 11:35:44 +0800 Subject: [PATCH 08/34] add helper method ty_with_projections for base --- src/librustc/mir/tcx.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index d55ca97a8dd6f..80e693b343f5f 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -214,6 +214,21 @@ impl<'tcx> PlaceBase<'tcx> { PlaceBase::Static(data) => data.ty, } } + + pub fn ty_with_projections( + &self, + local_decls: &impl HasLocalDecls<'tcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + elems: impl Iterator>, + ) -> Ty<'tcx> { + let mut base_ty = self.ty(local_decls); + + for elem in elems { + base_ty = PlaceTy::from(base_ty).projection_ty(tcx, elem).to_ty(tcx); + } + + base_ty + } } impl<'tcx> NeoPlace<'tcx> { From eab6d545ceb19d33663ee4dfcdf6c06e3c430f05 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 26 Sep 2018 16:32:55 +0800 Subject: [PATCH 09/34] add helper method to get base of place without projections --- src/librustc/mir/tcx.rs | 9 +++++++-- src/librustc_mir/borrow_check/borrow_set.rs | 17 ++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 80e693b343f5f..1dd57cafb30ee 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -299,8 +299,13 @@ impl<'tcx> NeoPlace<'tcx> { } } - pub fn has_no_projection(&self) -> bool { - self.elems.is_empty() + // Return the base of place without projections + pub fn bare_place(&self) -> Option<&PlaceBase<'tcx>>{ + if self.elems.is_empty() { + Some(&self.base) + } else { + None + } } } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index d650f6bd721f2..d33332bffb54c 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -346,15 +346,14 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { // // so extract `temp`. let neo_place = self.tcx.as_new_place(assigned_place); - let temp = match neo_place.base { - mir::PlaceBase::Local(temp) if neo_place.has_no_projection() => temp, - _ => { - span_bug!( - self.mir.source_info(start_location).span, - "expected 2-phase borrow to assign to a local, not `{:?}`", - assigned_place, - ); - } + let temp = if let Some(mir::PlaceBase::Local(temp)) = neo_place.bare_place() { + *temp + } else { + span_bug!( + self.mir.source_info(start_location).span, + "expected 2-phase borrow to assign to a local, not `{:?}`", + assigned_place, + ); }; // Consider the borrow not activated to start. When we find an activation, we'll update From 5779b683e661e823a1c089daaffae8ca01922b32 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 26 Sep 2018 17:14:44 +0800 Subject: [PATCH 10/34] implement construct method for NeoPlace --- src/librustc/mir/mod.rs | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index acaaeb5a36481..6e9c2419e337f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2090,6 +2090,91 @@ impl<'tcx> Place<'tcx> { } } +impl<'tcx> NeoPlace<'tcx> { + pub fn local(local: Local) -> Self { + Self { + base: PlaceBase::Local(local), + elems: List::empty(), + } + } + + pub fn static_(static_: Static<'tcx>) -> Self { + Self { + base: PlaceBase::Static(box static_), + elems: List::empty(), + } + } + + pub fn promoted(promoted: Promoted, ty: Ty<'tcx>) -> Self { + Self { + base: PlaceBase::Promoted(box (promoted, ty)), + elems: List::empty(), + } + } + + pub fn field( + self, + tcx: TyCtxt<'_, '_, 'tcx>, + f: Field, + ty: Ty<'tcx>, + ) -> Self { + self.elem(tcx, ProjectionElem::Field(f, ty)) + } + + pub fn deref(self, tcx: TyCtxt<'_, '_, 'tcx>) -> Self { + self.elem(tcx, ProjectionElem::Deref) + } + + pub fn downcast( + self, + tcx: TyCtxt<'_, '_, 'tcx>, + adt_def: &'tcx AdtDef, + variant_index: usize, + ) -> Self { + self.elem(tcx, ProjectionElem::Downcast(adt_def, variant_index)) + } + + pub fn index(self, tcx: TyCtxt<'_, '_, 'tcx>, index: Local) -> Self { + self.elem(tcx, ProjectionElem::Index(index)) + } + + pub fn constant_index( + self, + tcx: TyCtxt<'_, '_, 'tcx>, + offset: u32, + min_length: u32, + from_end: bool, + ) -> Self { + self.elem(tcx, ProjectionElem::ConstantIndex { + offset, min_length, from_end, + }) + } + + pub fn subslice( + self, + tcx: TyCtxt<'_, '_, 'tcx>, + from: u32, + to: u32, + ) -> Self { + self.elem(tcx, ProjectionElem::Subslice { + from, to, + }) + } + + fn elem( + self, + tcx: TyCtxt<'_, '_, 'tcx>, + elem: PlaceElem<'tcx>, + ) -> Self { + Self { + base: self.base, + elems: tcx.mk_place_elems( + self.elems.iter().cloned().chain(iter::once(elem)) + ), + } + } +} + impl<'tcx> Debug for Place<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Place::*; From bdcacb3652ed3073137dd9402053d06ab9dd3706 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 26 Sep 2018 18:37:06 +0800 Subject: [PATCH 11/34] add prefix method for neoplace --- src/librustc/mir/tcx.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 1dd57cafb30ee..fa7adab12adb5 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -307,6 +307,35 @@ impl<'tcx> NeoPlace<'tcx> { None } } + + // for a place_elem returns it's prefix path + // Base.[a, b, c] + // ^-- place_elem + // ^^^^^^^-- prefix + pub fn prefix<'cx, 'gcx>( + &self, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + elem_index: usize, + ) -> Self { + // only works for place with projections + assert!(!self.elems.is_empty()); + + if elem_index < 1 { + // Base.[a] + // ^-- elems[0] + Self { + base: self.clone().base, + elems: List::empty(), + } + } else { + Self { + base: self.clone().base, + elems: tcx.mk_place_elems( + self.elems.iter().cloned().take(elem_index) + ) + } + } + } } pub enum RvalueInitializationState { From dc3ad668fc7bcf1cb3731197e256ce61a4d8dddd Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 28 Sep 2018 19:02:32 +0800 Subject: [PATCH 12/34] rename bare_place to as_place_base --- src/librustc/mir/tcx.rs | 2 +- src/librustc_mir/borrow_check/borrow_set.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index fa7adab12adb5..150d9678d9579 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -300,7 +300,7 @@ impl<'tcx> NeoPlace<'tcx> { } // Return the base of place without projections - pub fn bare_place(&self) -> Option<&PlaceBase<'tcx>>{ + pub fn as_place_base(&self) -> Option<&PlaceBase<'tcx>>{ if self.elems.is_empty() { Some(&self.base) } else { diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index d33332bffb54c..b788540e12678 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -346,7 +346,8 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> { // // so extract `temp`. let neo_place = self.tcx.as_new_place(assigned_place); - let temp = if let Some(mir::PlaceBase::Local(temp)) = neo_place.bare_place() { + let temp = + if let Some(mir::PlaceBase::Local(temp)) = neo_place.as_place_base() { *temp } else { span_bug!( From 2286719f8149ec338477e6bd085aa9f50ccf7317 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 28 Sep 2018 21:31:42 +0800 Subject: [PATCH 13/34] optimize prefix method --- src/librustc/mir/mod.rs | 2 +- src/librustc/mir/tcx.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 6e9c2419e337f..d5680ad2b8f86 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2222,7 +2222,7 @@ impl<'tcx> Debug for Place<'tcx> { } impl<'tcx> Debug for PlaceBase<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::PlaceBase::*; match self { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 150d9678d9579..26a1dfe6f6ef4 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -330,9 +330,7 @@ impl<'tcx> NeoPlace<'tcx> { } else { Self { base: self.clone().base, - elems: tcx.mk_place_elems( - self.elems.iter().cloned().take(elem_index) - ) + elems: tcx.mk_place_elems(self.elems[..elem_index].iter()), } } } From 64c85e5a3d5a90cb4bb446eaa310b581517cfe19 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 10 Oct 2018 21:35:30 +0800 Subject: [PATCH 14/34] introduce neoplace in dataflow/impls --- src/librustc_mir/dataflow/impls/borrows.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 0ceff4aa04898..4b54f959ae2d0 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -4,6 +4,7 @@ use borrow_check::place_ext::PlaceExt; use rustc::mir::{self, Location, Place, Mir}; use rustc::ty::TyCtxt; use rustc::ty::RegionVid; +use rustc::mir::PlaceBase; use rustc_data_structures::bit_set::{BitSet, BitSetOperator}; use rustc_data_structures::fx::FxHashMap; @@ -188,8 +189,9 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { place: &Place<'tcx> ) { debug!("kill_borrows_on_place: place={:?}", place); - // Handle the `Place::Local(..)` case first and exit early. - if let Place::Local(local) = place { + // Handle the `PlaceBase::Local(..)` case first and exit early. + let neo_place = self.tcx.as_new_place(place); + if let Some(PlaceBase::Local(local)) = neo_place.as_place_base() { if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { debug!("kill_borrows_on_place: borrow_indices={:?}", borrow_indices); sets.kill_all(borrow_indices); @@ -260,13 +262,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { }); debug!("Borrows::statement_effect: stmt={:?}", stmt); - match stmt.kind { - mir::StatementKind::Assign(ref lhs, ref rhs) => { + match &stmt.kind { + mir::StatementKind::Assign(lhs, rhs) => { // Make sure there are no remaining borrows for variables // that are assigned over. self.kill_borrows_on_place(sets, lhs); - if let mir::Rvalue::Ref(_, _, ref place) = **rhs { + if let box mir::Rvalue::Ref(_, _, place) = rhs { if place.ignore_borrow( self.tcx, self.mir, @@ -285,7 +287,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { mir::StatementKind::StorageDead(local) => { // Make sure there are no remaining borrows for locals that // are gone out of scope. - self.kill_borrows_on_place(sets, &Place::Local(local)); + self.kill_borrows_on_place(sets, &Place::Local(*local)); } mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => { From 003b78c170880b86b81ebdffda73671dfba8ce26 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 10 Oct 2018 21:35:30 +0800 Subject: [PATCH 15/34] introduce neoplace in dataflow/impls --- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 4b54f959ae2d0..5e59e1dc11fee 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -2,9 +2,9 @@ use borrow_check::borrow_set::{BorrowSet, BorrowData}; use borrow_check::place_ext::PlaceExt; use rustc::mir::{self, Location, Place, Mir}; +use rustc::mir::PlaceBase; use rustc::ty::TyCtxt; use rustc::ty::RegionVid; -use rustc::mir::PlaceBase; use rustc_data_structures::bit_set::{BitSet, BitSetOperator}; use rustc_data_structures::fx::FxHashMap; From 971d0936443cf2807a92898c92dc26b5cd1ff1b2 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 17 Oct 2018 21:18:30 +0800 Subject: [PATCH 16/34] clean up old place in place_ext --- src/librustc_mir/borrow_check/borrow_set.rs | 3 +- src/librustc_mir/borrow_check/place_ext.rs | 73 ++++++++------------- 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index b788540e12678..34fa959889937 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -212,7 +212,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx); - if let Some(local) = borrowed_place.root_local() { + let neo_place = self.tcx.as_new_place(borrowed_place); + if let mir::PlaceBase::Local(local) = neo_place.base { self.local_map.entry(local).or_default().insert(idx); } } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 4d0b25b1024a3..c55975a1774f7 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -1,6 +1,7 @@ use rustc::hir; use rustc::mir::ProjectionElem; -use rustc::mir::{Local, Mir, Place, Mutability}; +use rustc::mir::{Mir, Place, PlaceBase, Mutability}; +use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, TyCtxt}; use borrow_check::borrow_set::LocalsStateAtExit; @@ -16,10 +17,6 @@ crate trait PlaceExt<'tcx> { mir: &Mir<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool; - - /// If this is a place like `x.f.g`, returns the local - /// `x`. Returns `None` if this is based in a static. - fn root_local(&self) -> Option; } impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { @@ -29,9 +26,8 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { mir: &Mir<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool { - match self { - Place::Promoted(_) => false, - + let neo_place = tcx.as_new_place(self); + let mut is_unsafe_place = match &neo_place.base { // If a local variable is immutable, then we only need to track borrows to guard // against two kinds of errors: // * The variable being dropped while still borrowed (e.g., because the fn returns @@ -40,7 +36,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { // // In particular, the variable cannot be mutated -- the "access checks" will fail -- // so we don't have to worry about mutation while borrowed. - Place::Local(index) => { + PlaceBase::Local(index) => { match locals_state_at_exit { LocalsStateAtExit::AllAreInvalidated => false, LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { @@ -50,48 +46,33 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { ignore } } - } - Place::Static(static_) => { + }, + PlaceBase::Promoted(_) => false, + PlaceBase::Static(static_) => { tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable) } - Place::Projection(proj) => match proj.elem { - ProjectionElem::Field(..) - | ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Index(_) => proj.base.ignore_borrow( - tcx, mir, locals_state_at_exit), + }; - ProjectionElem::Deref => { - let ty = proj.base.ty(mir, tcx).to_ty(tcx); - match ty.sty { - // For both derefs of raw pointers and `&T` - // references, the original path is `Copy` and - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true, - _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit), - } + let mut base_ty = neo_place.base.ty(mir); + for elem in neo_place.elems.iter() { + if let ProjectionElem::Deref = elem { + if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = base_ty.sty { + // For both derefs of raw pointers and `&T` + // references, the original path is `Copy` and + // therefore not significant. In particular, + // there is nothing the user can do to the + // original path that would invalidate the + // newly created reference -- and if there + // were, then the user could have copied the + // original path into a new variable and + // borrowed *that* one, leaving the original + // path unborrowed. + is_unsafe_place = true; } - }, - } - } - - fn root_local(&self) -> Option { - let mut p = self; - loop { - match p { - Place::Projection(pi) => p = &pi.base, - Place::Promoted(_) | - Place::Static(_) => return None, - Place::Local(l) => return Some(*l), } + base_ty = PlaceTy::from(base_ty).projection_ty(tcx, elem).to_ty(tcx); } + + is_unsafe_place } } From 4420ffff3a4ceeeb40a9851f968546bff3781fbd Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Thu, 18 Oct 2018 11:13:34 +0800 Subject: [PATCH 17/34] impl hash_stable for neo_place --- src/librustc/ich/impls_mir.rs | 43 ++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 002ac7cc7a9bb..36f1d024d9580 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -220,6 +220,27 @@ impl<'a, 'gcx> HashStable> for mir::Place<'gcx> { } } +impl<'a, 'gcx> HashStable> for mir::PlaceBase<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match self { + mir::PlaceBase::Local(local) => { + local.hash_stable(hcx, hasher); + } + mir::PlaceBase::Static(statik) => { + statik.hash_stable(hcx, hasher); + } + mir::PlaceBase::Promoted(promoted) => { + promoted.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::NeoPlace<'tcx> { base, elems }); + impl<'a, 'gcx, B, V, T> HashStable> for mir::Projection<'gcx, B, V, T> where B: HashStable>, @@ -322,45 +343,45 @@ impl<'a, 'gcx> HashStable> for mir::Rvalue<'gcx> { hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - mir::Rvalue::Use(ref operand) => { + match self { + mir::Rvalue::Use(operand) => { operand.hash_stable(hcx, hasher); } - mir::Rvalue::Repeat(ref operand, ref val) => { + mir::Rvalue::Repeat(operand, val) => { operand.hash_stable(hcx, hasher); val.hash_stable(hcx, hasher); } - mir::Rvalue::Ref(region, borrow_kind, ref place) => { + mir::Rvalue::Ref(region, borrow_kind, place) => { region.hash_stable(hcx, hasher); borrow_kind.hash_stable(hcx, hasher); place.hash_stable(hcx, hasher); } - mir::Rvalue::Len(ref place) => { + mir::Rvalue::Len(place) => { place.hash_stable(hcx, hasher); } - mir::Rvalue::Cast(cast_kind, ref operand, ty) => { + mir::Rvalue::Cast(cast_kind, operand, ty) => { cast_kind.hash_stable(hcx, hasher); operand.hash_stable(hcx, hasher); ty.hash_stable(hcx, hasher); } - mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) | - mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => { + mir::Rvalue::BinaryOp(op, operand1, operand2) | + mir::Rvalue::CheckedBinaryOp(op, operand1, operand2) => { op.hash_stable(hcx, hasher); operand1.hash_stable(hcx, hasher); operand2.hash_stable(hcx, hasher); } - mir::Rvalue::UnaryOp(op, ref operand) => { + mir::Rvalue::UnaryOp(op, operand) => { op.hash_stable(hcx, hasher); operand.hash_stable(hcx, hasher); } - mir::Rvalue::Discriminant(ref place) => { + mir::Rvalue::Discriminant(place) => { place.hash_stable(hcx, hasher); } mir::Rvalue::NullaryOp(op, ty) => { op.hash_stable(hcx, hasher); ty.hash_stable(hcx, hasher); } - mir::Rvalue::Aggregate(ref kind, ref operands) => { + mir::Rvalue::Aggregate(kind, operands) => { kind.hash_stable(hcx, hasher); operands.hash_stable(hcx, hasher); } From 8ca7fc6a8fb4c43bc9459f78f85e59c02ac6497e Mon Sep 17 00:00:00 2001 From: csmoe Date: Sun, 18 Nov 2018 13:29:01 +0800 Subject: [PATCH 18/34] generate tys of sub-places --- src/librustc/mir/mod.rs | 8 ++++--- src/librustc/mir/tcx.rs | 23 +++++++++++++++++++ src/librustc/mir/visit.rs | 1 - src/librustc_mir/borrow_check/borrow_set.rs | 7 ++++++ .../borrow_check/nll/type_check/mod.rs | 2 +- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d5680ad2b8f86..d15f953dd50a4 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2129,7 +2129,7 @@ impl<'tcx> NeoPlace<'tcx> { self, tcx: TyCtxt<'_, '_, 'tcx>, adt_def: &'tcx AdtDef, - variant_index: usize, + variant_index: VariantIdx, ) -> Self { self.elem(tcx, ProjectionElem::Downcast(adt_def, variant_index)) } @@ -3619,7 +3619,9 @@ where V: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>, { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + default fn super_fold_with<'gcx: 'tcx, F>(&self, folder: &mut F) -> Self + where F: TypeFolder<'gcx, 'tcx> + { use self::ProjectionElem::*; match self { Deref => Deref, @@ -3629,7 +3631,7 @@ where } } - fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + default fn super_visit_with>(&self, visitor: &mut Vs) -> bool { use self::ProjectionElem::*; match self { Field(_, ty) => ty.visit_with(visitor), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 26a1dfe6f6ef4..6e1eda478cedd 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -334,6 +334,29 @@ impl<'tcx> NeoPlace<'tcx> { } } } + + // Generate types of sub-places + // + // Base.[a, b] + // ^^^^-- base_ty + // ^^^^^^^-- elem1_ty + // ^^^^^^^^^^--elem2_ty + // + // [base_ty, elem1_ty, elem2_ty] + pub fn place_tys<'cx, 'gcx>( + &self, + mir: &'cx Mir<'tcx>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + ) -> Vec> { + let mut base_ty = PlaceTy::from(self.base.ty(mir)); + let mut place_tys: Vec> = vec![base_ty]; + for elem in self.elems.iter() { + let elem_ty = base_ty.projection_ty(tcx, elem); + place_tys.push(elem_ty); + base_ty = elem_ty; + } + place_tys + } } pub enum RvalueInitializationState { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ea07dee5be4c9..250625ee0dc8b 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -788,7 +788,6 @@ macro_rules! make_mir_visitor { for elem in elems.iter().cloned().rev() { self.visit_projection_elem( &$($mutability)* elem.clone(), - context, location ); } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 34fa959889937..6e90f66e8d164 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -8,6 +8,13 @@ use rustc::mir::visit::{ }; use rustc::mir::{self, Location, Mir, Local}; use rustc::ty::{RegionVid, TyCtxt}; +<<<<<<< HEAD +||||||| merged common ancestors +use rustc::mir::PlaceBase; +use rustc::ty::{RegionVid, TyCtxt}; +======= +use rustc::mir::PlaceBase; +>>>>>>> generate tys of sub-places use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::bit_set::BitSet; diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 3e6aa358ee0d1..ed8859d7964a7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1096,7 +1096,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); let annotated_type = self.mir.user_type_annotations[user_ty.base].inferred_ty; - let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); + let mut curr_projected_ty = PlaceTy::from(annotated_type); let tcx = self.infcx.tcx; From 63167badeb30f4887b58d4724c075cfe39fdfacb Mon Sep 17 00:00:00 2001 From: csmoe Date: Mon, 19 Nov 2018 10:27:40 +0800 Subject: [PATCH 19/34] generate prefixes for place --- src/librustc/mir/tcx.rs | 17 ++++++++++++++--- src/librustc_mir/borrow_check/borrow_set.rs | 7 ------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 6e1eda478cedd..8413addad1b79 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -317,9 +317,6 @@ impl<'tcx> NeoPlace<'tcx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, elem_index: usize, ) -> Self { - // only works for place with projections - assert!(!self.elems.is_empty()); - if elem_index < 1 { // Base.[a] // ^-- elems[0] @@ -335,6 +332,20 @@ impl<'tcx> NeoPlace<'tcx> { } } + pub fn prefixes<'cx, 'gcx>( + &self, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + ) -> Vec { + // only works for place with projections + assert!(!self.elems.is_empty()); + + self.elems + .iter() + .enumerate() + .map(|(elem_index, _)| self.prefix(tcx, elem_index)) + .collect::>>() + } + // Generate types of sub-places // // Base.[a, b] diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 6e90f66e8d164..34fa959889937 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -8,13 +8,6 @@ use rustc::mir::visit::{ }; use rustc::mir::{self, Location, Mir, Local}; use rustc::ty::{RegionVid, TyCtxt}; -<<<<<<< HEAD -||||||| merged common ancestors -use rustc::mir::PlaceBase; -use rustc::ty::{RegionVid, TyCtxt}; -======= -use rustc::mir::PlaceBase; ->>>>>>> generate tys of sub-places use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::bit_set::BitSet; From 7f084ecd485f3a654a6c803b2ff80a3bd533b754 Mon Sep 17 00:00:00 2001 From: csmoe Date: Mon, 19 Nov 2018 15:37:40 +0800 Subject: [PATCH 20/34] rewrite places conflict --- .../borrow_check/places_conflict.rs | 567 +++++++++--------- 1 file changed, 281 insertions(+), 286 deletions(-) diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index ac7182abb36da..b4a32e546434a 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -1,9 +1,11 @@ use borrow_check::ArtificialField; use borrow_check::Overlap; -use borrow_check::{Deep, Shallow, AccessDepth}; +use borrow_check::{AccessDepth, Deep, Shallow}; use rustc::hir; use rustc::mir::{BorrowKind, Mir, Place}; -use rustc::mir::{Projection, ProjectionElem}; +use rustc::mir::{NeoPlace, PlaceBase, ProjectionElem}; +use rustc::mir::PlaceElem; +use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -33,7 +35,9 @@ crate fn places_conflict<'gcx, 'tcx>( tcx, mir, borrow_place, - BorrowKind::Mut { allow_two_phase_borrow: true }, + BorrowKind::Mut { + allow_two_phase_borrow: true, + }, access_place, AccessDepth::Deep, bias, @@ -53,40 +57,41 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>( access: AccessDepth, bias: PlaceConflictBias, ) -> bool { + let borrow_place = &tcx.as_new_place(borrow_place); + let access_place = &tcx.as_new_place(access_place); debug!( "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})", borrow_place, access_place, access, bias, ); - // This Local/Local case is handled by the more general code below, but - // it's so common that it's a speed win to check for it first. - if let Place::Local(l1) = borrow_place { - if let Place::Local(l2) = access_place { - return l1 == l2; + match place_base_conflict(tcx, &borrow_place.base, &access_place.base) { + // process to projections to check further conflict. + Overlap::EqualOrDisjoint => place_elems_conflict( + tcx, + mir, + &borrow_place, + &access_place, + borrow_kind, + access, + bias, + ), + Overlap::Disjoint => { + // We have proven the borrow disjoint - further + // projections will remain disjoint. + debug!("borrow_conflicts_with_place: disjoint"); + false } + // place.base overlap is obvious, no Abitrary. + _ => unreachable!(), } - - unroll_place(borrow_place, None, |borrow_components| { - unroll_place(access_place, None, |access_components| { - place_components_conflict( - tcx, - mir, - borrow_components, - borrow_kind, - access_components, - access, - bias, - ) - }) - }) } -fn place_components_conflict<'gcx, 'tcx>( +fn place_elems_conflict<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, - mut borrow_components: PlaceComponentsIter<'_, 'tcx>, + borrow_place: &NeoPlace<'tcx>, + access_place: &NeoPlace<'tcx>, borrow_kind: BorrowKind, - mut access_components: PlaceComponentsIter<'_, 'tcx>, access: AccessDepth, bias: PlaceConflictBias, ) -> bool { @@ -131,27 +136,36 @@ fn place_components_conflict<'gcx, 'tcx>( // - If we didn't run out of access to match, our borrow and access are comparable // and either equal or disjoint. // - If we did run out of access, the borrow can access a part of it. + let mut borrow_elems = borrow_place.elems.iter(); + let mut access_elems = access_place.elems.iter(); + let mut borrow_base_ty = borrow_place.base.ty(mir); loop { // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - if let Some(borrow_c) = borrow_components.next() { - debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); + if let Some(borrow_elem) = borrow_elems.next() { + debug!( + "borrow_conflicts_with_place: borrow_elem = {:?}", + borrow_elem + ); - if let Some(access_c) = access_components.next() { - debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); + if let Some(access_elem) = access_elems.next() { + debug!( + "borrow_conflicts_with_place: access_elem = {:?}", + access_elem + ); - // Borrow and access path both have more components. + // Borrow and access path both have more elements. // // Examples: // // - borrow of `a.(...)`, access to `a.(...)` // - borrow of `a.(...)`, access to `b.(...)` // - // Here we only see the components we have checked so - // far (in our examples, just the first component). We - // check whether the components being borrowed vs + // Here we only see the elements we have checked so + // far (in our examples, just the first element). We + // check whether the elements being borrowed vs // accessed are disjoint (as in the second example, // but not the first). - match place_element_conflict(tcx, mir, borrow_c, access_c, bias) { + match place_element_conflict(borrow_elem, access_elem, bias, borrow_base_ty) { Overlap::Arbitrary => { // We have encountered different fields of potentially // the same union - the borrow now partially overlaps. @@ -188,13 +202,7 @@ fn place_components_conflict<'gcx, 'tcx>( // our place. This is a conflict if that is a part our // access cares about. - let (base, elem) = match borrow_c { - Place::Projection(box Projection { base, elem }) => (base, elem), - _ => bug!("place has no base?"), - }; - let base_ty = base.ty(mir, tcx).to_ty(tcx); - - match (elem, &base_ty.sty, access) { + match (borrow_elem, &borrow_base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { // The array length is like additional fields on the @@ -248,6 +256,9 @@ fn place_components_conflict<'gcx, 'tcx>( } } } + borrow_base_ty = PlaceTy::from(borrow_base_ty) + .projection_ty(tcx, &borrow_elem) + .to_ty(tcx); } else { // Borrow path ran out but access path may not // have. Examples: @@ -262,7 +273,7 @@ fn place_components_conflict<'gcx, 'tcx>( // If the second example, where we did, then we still know // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() { + if borrow_kind == BorrowKind::Shallow && access_elems.next().is_some() { debug!("borrow_conflicts_with_place: shallow borrow"); return false; } else { @@ -273,95 +284,13 @@ fn place_components_conflict<'gcx, 'tcx>( } } -/// A linked list of places running up the stack; begins with the -/// innermost place and extends to projections (e.g., `a.b` would have -/// the place `a` with a "next" pointer to `a.b`). Created by -/// `unroll_place`. -/// -/// N.B., this particular impl strategy is not the most obvious. It was -/// chosen because it makes a measurable difference to NLL -/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. -struct PlaceComponents<'p, 'tcx: 'p> { - component: &'p Place<'tcx>, - next: Option<&'p PlaceComponents<'p, 'tcx>>, -} - -impl<'p, 'tcx> PlaceComponents<'p, 'tcx> { - /// Converts a list of `Place` components into an iterator; this - /// iterator yields up a never-ending stream of `Option<&Place>`. - /// These begin with the "innermost" place and then with each - /// projection therefrom. So given a place like `a.b.c` it would - /// yield up: - /// - /// ```notrust - /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ... - /// ``` - fn iter(&self) -> PlaceComponentsIter<'_, 'tcx> { - PlaceComponentsIter { value: Some(self) } - } -} - -/// Iterator over components; see `PlaceComponents::iter` for more -/// information. -/// -/// N.B., this is not a *true* Rust iterator -- the code above just -/// manually invokes `next`. This is because we (sometimes) want to -/// keep executing even after `None` has been returned. -struct PlaceComponentsIter<'p, 'tcx: 'p> { - value: Option<&'p PlaceComponents<'p, 'tcx>>, -} - -impl<'p, 'tcx> PlaceComponentsIter<'p, 'tcx> { - fn next(&mut self) -> Option<&'p Place<'tcx>> { - if let Some(&PlaceComponents { component, next }) = self.value { - self.value = next; - Some(component) - } else { - None - } - } -} - -/// Recursively "unroll" a place into a `PlaceComponents` list, -/// invoking `op` with a `PlaceComponentsIter`. -fn unroll_place<'tcx, R>( - place: &Place<'tcx>, - next: Option<&PlaceComponents<'_, 'tcx>>, - op: impl FnOnce(PlaceComponentsIter<'_, 'tcx>) -> R, -) -> R { - match place { - Place::Projection(interior) => unroll_place( - &interior.base, - Some(&PlaceComponents { - component: place, - next, - }), - op, - ), - - Place::Promoted(_) | - Place::Local(_) | Place::Static(_) => { - let list = PlaceComponents { - component: place, - next, - }; - op(list.iter()) - } - } -} - -// Given that the bases of `elem1` and `elem2` are always either equal -// or disjoint (and have the same type!), return the overlap situation -// between `elem1` and `elem2`. -fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( +fn place_base_conflict<'a, 'gcx: 'tcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, - mir: &Mir<'tcx>, - elem1: &Place<'tcx>, - elem2: &Place<'tcx>, - bias: PlaceConflictBias, + base1: &PlaceBase<'tcx>, + base2: &PlaceBase<'tcx>, ) -> Overlap { - match (elem1, elem2) { - (Place::Local(l1), Place::Local(l2)) => { + match (base1, base2) { + (PlaceBase::Local(l1), PlaceBase::Local(l2)) => { if l1 == l2 { // the same local - base case, equal debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL"); @@ -372,7 +301,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( Overlap::Disjoint } } - (Place::Static(static1), Place::Static(static2)) => { + (PlaceBase::Static(static1), PlaceBase::Static(static2)) => { if static1.def_id != static2.def_id { debug!("place_element_conflict: DISJOINT-STATIC"); Overlap::Disjoint @@ -385,7 +314,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( Overlap::EqualOrDisjoint } } - (Place::Promoted(p1), Place::Promoted(p2)) => { + (PlaceBase::Promoted(p1), PlaceBase::Promoted(p2)) => { if p1.0 == p2.0 { if let ty::Array(_, size) = p1.1.sty { if size.unwrap_usize(tcx) == 0 { @@ -403,173 +332,239 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( Overlap::Disjoint } } - (Place::Local(_), Place::Promoted(_)) | (Place::Promoted(_), Place::Local(_)) | - (Place::Promoted(_), Place::Static(_)) | (Place::Static(_), Place::Promoted(_)) | - (Place::Local(_), Place::Static(_)) | (Place::Static(_), Place::Local(_)) => { + (PlaceBase::Local(_), PlaceBase::Promoted(_)) + | (PlaceBase::Promoted(_), PlaceBase::Local(_)) + | (PlaceBase::Promoted(_), PlaceBase::Static(_)) + | (PlaceBase::Static(_), PlaceBase::Promoted(_)) + | (PlaceBase::Local(_), PlaceBase::Static(_)) + | (PlaceBase::Static(_), PlaceBase::Local(_)) => { debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED"); Overlap::Disjoint } - (Place::Projection(pi1), Place::Projection(pi2)) => { - match (&pi1.elem, &pi2.elem) { - (ProjectionElem::Deref, ProjectionElem::Deref) => { - // derefs (e.g., `*x` vs. `*x`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); - Overlap::EqualOrDisjoint - } - (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { - if f1 == f2 { - // same field (e.g., `a.y` vs. `a.y`) - recur. - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { - let ty = pi1.base.ty(mir, tcx).to_ty(tcx); - match ty.sty { - ty::Adt(def, _) if def.is_union() => { - // Different fields of a union, we are basically stuck. - debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } - _ => { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } - } + } +} + +// Given that the bases of `elem1` and `elem2` are always either equal +// or disjoint (and have the same type!), return the overlap situation +// between `elem1` and `elem2`. +fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( + elem1: &PlaceElem<'tcx>, + elem2: &PlaceElem<'tcx>, + bias: PlaceConflictBias, + borrow_base_ty: rustc::ty::Ty<'tcx>, +) -> Overlap { + match (elem1, elem2) { + (ProjectionElem::Deref, ProjectionElem::Deref) => { + // derefs (e.g., `*x` vs. `*x`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); + Overlap::EqualOrDisjoint + } + (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { + if f1 == f2 { + // same field (e.g., `a.y` vs. `a.y`) - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + Overlap::EqualOrDisjoint + } else { + match borrow_base_ty.sty { + ty::Adt(def, _) if def.is_union() => { + // Different fields of a union, we are basically stuck. + debug!("place_element_conflict: STUCK-UNION"); + Overlap::Arbitrary } - } - (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { - // different variants are treated as having disjoint fields, - // even if they occupy the same "space", because it's - // impossible for 2 variants of the same enum to exist - // (and therefore, to be borrowed) at the same time. - // - // Note that this is different from unions - we *do* allow - // this code to compile: - // - // ``` - // fn foo(x: &mut Result) { - // let mut v = None; - // if let Ok(ref mut a) = *x { - // v = Some(a); - // } - // // here, you would *think* that the - // // *entirety* of `x` would be borrowed, - // // but in fact only the `Ok` variant is, - // // so the `Err` variant is *entirely free*: - // if let Err(ref mut a) = *x { - // v = Some(a); - // } - // drop(v); - // } - // ``` - if v1 == v2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); - Overlap::EqualOrDisjoint - } else { + _ => { + // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! debug!("place_element_conflict: DISJOINT-FIELD"); Overlap::Disjoint } } - (ProjectionElem::Index(..), ProjectionElem::Index(..)) - | (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. }) - | (ProjectionElem::Index(..), ProjectionElem::Subslice { .. }) - | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..)) - | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => { - // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint - // (if the indexes differ) or equal (if they are the same). - match bias { - PlaceConflictBias::Overlap => { - // If we are biased towards overlapping, then this is the recursive - // case that gives "equal *or* disjoint" its meaning. - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); - Overlap::EqualOrDisjoint - } - PlaceConflictBias::NoOverlap => { - // If we are biased towards no overlapping, then this is disjoint. - debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); - Overlap::Disjoint - } - } - } - (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, - ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }) - | (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, - ProjectionElem::ConstantIndex { - offset: o2, min_length: _, from_end: true }) => { - if o1 == o2 { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); - Overlap::Disjoint - } - } - (ProjectionElem::ConstantIndex { - offset: offset_from_begin, min_length: min_length1, from_end: false }, - ProjectionElem::ConstantIndex { - offset: offset_from_end, min_length: min_length2, from_end: true }) - | (ProjectionElem::ConstantIndex { - offset: offset_from_end, min_length: min_length1, from_end: true }, - ProjectionElem::ConstantIndex { - offset: offset_from_begin, min_length: min_length2, from_end: false }) => { - // both patterns matched so it must be at least the greater of the two - let min_length = max(min_length1, min_length2); - // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last - // element (like -1 in Python) and `min_length` the first. - // Therefore, `min_length - offset_from_end` gives the minimal possible - // offset from the beginning - if *offset_from_begin >= min_length - offset_from_end { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); - Overlap::Disjoint - } - } - (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, - ProjectionElem::Subslice {from, .. }) - | (ProjectionElem::Subslice {from, .. }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => { - if offset >= from { - debug!( - "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); - Overlap::Disjoint - } - } - (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, - ProjectionElem::Subslice {from: _, to }) - | (ProjectionElem::Subslice {from: _, to }, - ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => { - if offset > to { - debug!("place_element_conflict: \ - DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::EqualOrDisjoint - } else { - debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); - Overlap::Disjoint - } + } + } + (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => { + // different variants are treated as having disjoint fields, + // even if they occupy the same "space", because it's + // impossible for 2 variants of the same enum to exist + // (and therefore, to be borrowed) at the same time. + // + // Note that this is different from unions - we *do* allow + // this code to compile: + // + // ``` + // fn foo(x: &mut Result) { + // let mut v = None; + // if let Ok(ref mut a) = *x { + // v = Some(a); + // } + // // here, you would *think* that the + // // *entirety* of `x` would be borrowed, + // // but in fact only the `Ok` variant is, + // // so the `Err` variant is *entirely free*: + // if let Err(ref mut a) = *x { + // v = Some(a); + // } + // drop(v); + // } + // ``` + if v1 == v2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-FIELD"); + Overlap::Disjoint + } + } + (ProjectionElem::Index(..), ProjectionElem::Index(..)) + | (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. }) + | (ProjectionElem::Index(..), ProjectionElem::Subslice { .. }) + | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..)) + | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => { + // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint + // (if the indexes differ) or equal (if they are the same). + match bias { + PlaceConflictBias::Overlap => { + // If we are biased towards overlapping, then this is the recursive + // case that gives "equal *or* disjoint" its meaning. + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); + Overlap::EqualOrDisjoint } - (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); - Overlap::EqualOrDisjoint + PlaceConflictBias::NoOverlap => { + // If we are biased towards no overlapping, then this is disjoint. + debug!("place_element_conflict: DISJOINT-ARRAY-INDEX"); + Overlap::Disjoint } - (ProjectionElem::Deref, _) - | (ProjectionElem::Field(..), _) - | (ProjectionElem::Index(..), _) - | (ProjectionElem::ConstantIndex { .. }, _) - | (ProjectionElem::Subslice { .. }, _) - | (ProjectionElem::Downcast(..), _) => bug!( - "mismatched projections in place_element_conflict: {:?} and {:?}", - elem1, - elem2 - ), } } - (Place::Projection(_), _) | (_, Place::Projection(_)) => bug!( - "unexpected elements in place_element_conflict: {:?} and {:?}", + ( + ProjectionElem::ConstantIndex { + offset: o1, + min_length: _, + from_end: false, + }, + ProjectionElem::ConstantIndex { + offset: o2, + min_length: _, + from_end: false, + }, + ) + | ( + ProjectionElem::ConstantIndex { + offset: o1, + min_length: _, + from_end: true, + }, + ProjectionElem::ConstantIndex { + offset: o2, + min_length: _, + from_end: true, + }, + ) => { + if o1 == o2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { + offset: offset_from_begin, + min_length: min_length1, + from_end: false, + }, + ProjectionElem::ConstantIndex { + offset: offset_from_end, + min_length: min_length2, + from_end: true, + }, + ) + | ( + ProjectionElem::ConstantIndex { + offset: offset_from_end, + min_length: min_length1, + from_end: true, + }, + ProjectionElem::ConstantIndex { + offset: offset_from_begin, + min_length: min_length2, + from_end: false, + }, + ) => { + // both patterns matched so it must be at least the greater of the two + let min_length = max(min_length1, min_length2); + // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last + // element (like -1 in Python) and `min_length` the first. + // Therefore, `min_length - offset_from_end` gives the minimal possible + // offset from the beginning + if *offset_from_begin >= min_length - offset_from_end { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { + offset, + min_length: _, + from_end: false, + }, + ProjectionElem::Subslice { from, .. }, + ) + | ( + ProjectionElem::Subslice { from, .. }, + ProjectionElem::ConstantIndex { + offset, + min_length: _, + from_end: false, + }, + ) => { + if offset >= from { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::Disjoint + } + } + ( + ProjectionElem::ConstantIndex { + offset, + min_length: _, + from_end: true, + }, + ProjectionElem::Subslice { from: _, to }, + ) + | ( + ProjectionElem::Subslice { from: _, to }, + ProjectionElem::ConstantIndex { + offset, + min_length: _, + from_end: true, + }, + ) => { + if offset > to { + debug!( + "place_element_conflict: \ + DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE" + ); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::Disjoint + } + } + (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); + Overlap::EqualOrDisjoint + } + (ProjectionElem::Deref, _) + | (ProjectionElem::Field(..), _) + | (ProjectionElem::Index(..), _) + | (ProjectionElem::ConstantIndex { .. }, _) + | (ProjectionElem::Subslice { .. }, _) + | (ProjectionElem::Downcast(..), _) => bug!( + "mismatched projections in place_element_conflict: {:?} and {:?}", elem1, elem2 ), From 2d1dce883b46e7d6c3ba01fc0f7dac0f446fee6a Mon Sep 17 00:00:00 2001 From: csmoe Date: Tue, 20 Nov 2018 18:28:36 +0800 Subject: [PATCH 21/34] rewrite place in move_errs --- src/librustc_mir/borrow_check/move_errors.rs | 215 ++++++++++--------- 1 file changed, 114 insertions(+), 101 deletions(-) diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 34d5065f2ff98..a8f05dc41d062 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -111,39 +111,42 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // If that ever stops being the case, then the ever initialized // flow could be used. if let Some(StatementKind::Assign( - Place::Local(local), + place, box Rvalue::Use(Operand::Move(move_from)), )) = self.mir.basic_blocks()[location.block] .statements .get(location.statement_index) .map(|stmt| &stmt.kind) { - let local_decl = &self.mir.local_decls[*local]; - // opt_match_place is the - // match_span is the span of the expression being matched on - // match *x.y { ... } match_place is Some(*x.y) - // ^^^^ match_span is the span of *x.y - // - // opt_match_place is None for let [mut] x = ... statements, - // whether or not the right-hand side is a place expression - if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - }))) = local_decl.is_user_variable - { - self.append_binding_error( - grouped_errors, - kind, - original_path, - move_from, - *local, - opt_match_place, - match_span, - stmt_source_info.span, - ); - return; + let neo_place = self.infcx.tcx.as_new_place(&place); + if let Some(PlaceBase::Local(local)) = neo_place.as_place_base() { + let local_decl = &self.mir.local_decls[*local]; + // opt_match_place is the + // match_span is the span of the expression being matched on + // match *x.y { ... } match_place is Some(*x.y) + // ^^^^ match_span is the span of *x.y + // + // opt_match_place is None for let [mut] x = ... statements, + // whether or not the right-hand side is a place expression + if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + }))) = local_decl.is_user_variable + { + self.append_binding_error( + grouped_errors, + kind, + original_path, + move_from, + *local, + opt_match_place, + match_span, + stmt_source_info.span, + ); + return; + } } } grouped_errors.push(GroupedMoveError::OtherIllegalMove { @@ -269,12 +272,15 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let neo_place = self.infcx.tcx.as_new_place(&place); + let ty = neo_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let is_upvar_field_projection = self.prefixes(&original_path, PrefixSet::All) .map(|p| self.infcx.tcx.as_new_place(&p)) .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) - .is_some()); + .is_some() + ); debug!("report: ty={:?}", ty); match ty.sty { ty::Array(..) | ty::Slice(..) => @@ -354,52 +360,54 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { err: &mut DiagnosticBuilder<'a>, span: Span, ) { - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); - match error { - GroupedMoveError::MovesFromPlace { - mut binds_to, - move_from, - .. - } => { - let try_remove_deref = match move_from { - Place::Projection(box PlaceProjection { - elem: ProjectionElem::Deref, - .. - }) => true, - _ => false, - }; - if try_remove_deref && snippet.starts_with('*') { - // The snippet doesn't start with `*` in (e.g.) index - // expressions `a[b]`, which roughly desugar to - // `*Index::index(&a, b)` or - // `*IndexMut::index_mut(&mut a, b)`. - err.span_suggestion( - span, - "consider removing the `*`", - snippet[1..].to_owned(), - Applicability::Unspecified, - ); - } else { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); - } + if let Ok(snippet) = self.infcx.tcx.sess + .source_map().span_to_snippet(span) { + match error { + GroupedMoveError::MovesFromPlace { + mut binds_to, + move_from, + .. + } => { + let try_remove_deref = match move_from { + Place::Projection(box PlaceProjection { + elem: ProjectionElem::Deref, + .. + }) => true, + _ => false, + }; + if try_remove_deref && snippet.starts_with('*') { + // The snippet doesn't start with `*` in (e.g.) index + // expressions `a[b]`, which roughly desugar to + // `*Index::index(&a, b)` or + // `*IndexMut::index_mut(&mut a, b)`. + err.span_suggestion( + span, + "consider removing the `*`", + snippet[1..].to_owned(), + Applicability::Unspecified, + ); + } else { + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); + } - binds_to.sort(); - binds_to.dedup(); - self.add_move_error_details(err, &binds_to); - } - GroupedMoveError::MovesFromValue { mut binds_to, .. } => { - binds_to.sort(); - binds_to.dedup(); - self.add_move_error_suggestions(err, &binds_to); - self.add_move_error_details(err, &binds_to); + binds_to.sort(); + binds_to.dedup(); + self.add_move_error_details(err, &binds_to); + } + GroupedMoveError::MovesFromValue { mut binds_to, .. } => { + binds_to.sort(); + binds_to.dedup(); + self.add_move_error_suggestions(err, &binds_to); + self.add_move_error_details(err, &binds_to); + } + // No binding. Nothing to suggest. + GroupedMoveError::OtherIllegalMove { .. } => (), } - // No binding. Nothing to suggest. - GroupedMoveError::OtherIllegalMove { .. } => (), } } @@ -417,27 +425,28 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { .. })) ) = bind_to.is_user_variable { - let pat_snippet = self.infcx.tcx.sess.source_map() - .span_to_snippet(pat_span) - .unwrap(); - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); - let suggestion; - let to_remove; - if pat_snippet.starts_with("mut") - && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) - { - suggestion = pat_snippet["mut".len()..].trim_start(); - to_remove = "&mut"; - } else { - suggestion = pat_snippet; - to_remove = "&"; + if let Ok(pat_snippet) = self.infcx.tcx.sess + .source_map() + .span_to_snippet(pat_span) { + if pat_snippet.starts_with('&') { + let pat_snippet = pat_snippet[1..].trim_start(); + let suggestion; + let to_remove; + if pat_snippet.starts_with("mut") + && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) + { + suggestion = pat_snippet["mut".len()..].trim_start(); + to_remove = "&mut"; + } else { + suggestion = pat_snippet; + to_remove = "&"; + } + suggestions.push(( + pat_span, + to_remove, + suggestion.to_owned(), + )); } - suggestions.push(( - pat_span, - to_remove, - suggestion.to_owned(), - )); } } } @@ -536,7 +545,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // We're only interested in assignments (in particular, where the // assignment came from - was it an `Rc` or `Arc`?). if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind { - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let neo_place = self.infcx.tcx.as_new_place(source); + let ty = neo_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); let ty = match ty.sty { ty::TyKind::Ref(_, ty, _) => ty, _ => ty, @@ -560,8 +570,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { Operand::Copy(place) | Operand::Move(place) => place, _ => continue, }; - - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let neo_place = self.infcx.tcx.as_new_place(&source); + let ty = neo_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); let ty = match ty.sty { ty::TyKind::Ref(_, ty, _) => ty, _ => ty, @@ -583,11 +593,14 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // If we didn't find an `Arc` or an `Rc`, then check specifically for // a dereference of a place that has the type of a raw pointer. // We can't use `place.ty(..).to_ty(..)` here as that strips away the raw pointer. - if let Place::Projection(box Projection { - base, - elem: ProjectionElem::Deref, - }) = place { - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() { + let neo_place = self.infcx.tcx.as_new_place(&place); + let place_tys = neo_place.place_tys(&self.mir, self.infcx.tcx); + if let Some(&ProjectionElem::Deref) = neo_place.elems.last() { + // Given place + // base.[a, b, c] + // ^-- deref + // ^^^^^^^^^^ + if place_tys[place_tys.len() - 2].to_ty(self.infcx.tcx).is_unsafe_ptr() { return BorrowedContentSource::DerefRawPointer; } } From 7af3ddd7dc4d3841d77e0c9c4dfe5f0303a6fcca Mon Sep 17 00:00:00 2001 From: csmoe Date: Tue, 20 Nov 2018 21:15:10 +0800 Subject: [PATCH 22/34] introduce neo_place in borrowck/path_utils --- src/librustc_mir/borrow_check/mod.rs | 4 +- .../borrow_check/nll/invalidation.rs | 6 +- src/librustc_mir/borrow_check/path_utils.rs | 59 +++++++++++-------- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 335b07513a566..d8b9d0cf7e4ff 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1381,7 +1381,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) { debug!("check_for_local_borrow({:?})", borrow); - if borrow_of_local_data(&borrow.borrowed_place) { + let neo_place = self.infcx.tcx + .as_new_place(&borrow.borrowed_place); + if borrow_of_local_data(&neo_place) { let err = self.infcx.tcx .cannot_borrow_across_generator_yield( self.retrieve_borrow_spans(borrow).var_or_use(), diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 112b39952559b..4af004f437fcf 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -237,7 +237,8 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { let borrow_set = self.borrow_set.clone(); let resume = self.location_table.start_index(resume.start_location()); for i in borrow_set.borrows.indices() { - if borrow_of_local_data(&borrow_set.borrows[i].borrowed_place) { + let neo_place = self.tcx.as_new_place(&borrow_set.borrows[i].borrowed_place); + if borrow_of_local_data(&neo_place) { self.all_facts.invalidates.push((resume, i)); } } @@ -247,7 +248,8 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { let borrow_set = self.borrow_set.clone(); let start = self.location_table.start_index(location); for i in borrow_set.borrows.indices() { - if borrow_of_local_data(&borrow_set.borrows[i].borrowed_place) { + let neo_place = self.tcx.as_new_place(&borrow_set.borrows[i].borrowed_place); + if borrow_of_local_data(&neo_place) { self.all_facts.invalidates.push((start, i)); } } diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 6875aced8d231..af7ddddeade99 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -1,10 +1,11 @@ -use borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation}; +use borrow_check::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; use borrow_check::places_conflict; -use borrow_check::Context; use borrow_check::AccessDepth; +use borrow_check::Context; use dataflow::indexes::BorrowIndex; use rustc::mir::{BasicBlock, Location, Mir, Place}; -use rustc::mir::{ProjectionElem, BorrowKind}; +use rustc::mir::{BorrowKind, ProjectionElem}; +use rustc::mir::{NeoPlace, PlaceBase}; use rustc::ty::TyCtxt; use rustc_data_structures::graph::dominators::Dominators; @@ -13,11 +14,10 @@ use rustc_data_structures::graph::dominators::Dominators; /// Activation phases. pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>( tcx: &TyCtxt<'a, 'gcx, 'tcx>, - kind: BorrowKind + kind: BorrowKind, ) -> bool { tcx.two_phase_borrows() - && (kind.allows_two_phase_borrow() - || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) + && (kind.allows_two_phase_borrow() || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } /// Control for the path borrow checking code @@ -28,7 +28,7 @@ pub(super) enum Control { } /// Encapsulates the idea of iterating over every borrow that involves a particular path -pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( +pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S>( s: &mut S, tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, @@ -39,7 +39,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( mut op: F, ) where F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control, - I: Iterator + I: Iterator, { let (access, place) = access_place; @@ -75,9 +75,12 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( pub(super) fn is_active<'tcx>( dominators: &Dominators, borrow_data: &BorrowData<'tcx>, - location: Location + location: Location, ) -> bool { - debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location); + debug!( + "is_active(borrow_data={:?}, location={:?})", + borrow_data, location + ); let activation_location = match borrow_data.activation_location { // If this is not a 2-phase borrow, it is always active. @@ -136,24 +139,28 @@ pub(super) fn is_active<'tcx>( /// Determines if a given borrow is borrowing local data /// This is called for all Yield statements on movable generators -pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool { - match place { - Place::Promoted(_) | - Place::Static(..) => false, - Place::Local(..) => true, - Place::Projection(box proj) => { - match proj.elem { - // Reborrow of already borrowed data is ignored - // Any errors will be caught on the initial borrow - ProjectionElem::Deref => false, +pub(super) fn borrow_of_local_data<'tcx>(place: &NeoPlace<'tcx>) -> bool { + let mut borrow_of_local_data = match place.base { + PlaceBase::Promoted(_) | PlaceBase::Static(..) => false, + PlaceBase::Local(..) => true, + }; - // For interior references and downcasts, find out if the base is local - ProjectionElem::Field(..) - | ProjectionElem::Index(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base), + for elem in place.elems.iter().rev() { + match elem { + // Reborrow of already borrowed data is ignored + // Any errors will be caught on the initial borrow + ProjectionElem::Deref => { + borrow_of_local_data = false; + break; } + + // For interior references and downcasts, find out if the base is local + ProjectionElem::Field(..) + | ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(..) => {} } } + borrow_of_local_data } From 53e604cfd3a0d054214ada4ed3303ef95e80fdf5 Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 22 Nov 2018 16:35:17 +0800 Subject: [PATCH 23/34] rewrite place in used_muts into neo_place --- src/librustc_mir/borrow_check/used_muts.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 0ff7ff4de10de..6f338158af3bd 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -1,5 +1,6 @@ use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{BasicBlock, Local, Location, Place, Statement, StatementKind, TerminatorKind}; +use rustc::mir::{BasicBlock, Local, Location, Statement, StatementKind, TerminatorKind}; +use rustc::mir::PlaceBase; use rustc_data_structures::fx::FxHashSet; @@ -114,8 +115,9 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c "assignment of {:?} to {:?}, adding {:?} to used mutable set", path.place, local, path.place ); - if let Place::Local(user_local) = path.place { - self.mbcx.used_mut.insert(user_local); + let neo_place = self.mbcx.infcx.tcx.as_new_place(&path.place); + if let Some(PlaceBase::Local(user_local)) = neo_place.as_place_base() { + self.mbcx.used_mut.insert(*user_local); } } } From 6eb57e9fc4fcd132450ed8e3603b96ef0fcc4aff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Jan 2019 12:14:15 -0500 Subject: [PATCH 24/34] introduce NeoPlaceTree --- src/librustc/mir/mod.rs | 56 ++++++++++++++++++++++++++--- src/librustc/ty/structural_impls.rs | 11 ++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d15f953dd50a4..f334ef1397b8f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1907,13 +1907,59 @@ pub enum Place<'tcx> { } /// A new Place repr -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct NeoPlace<'tcx> { pub base: PlaceBase<'tcx>, - pub elems: &'tcx List>, + pub elems: &'tcx [PlaceElem<'tcx>], } -impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List> {} +// FIXME +// impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List> {} + +impl NeoPlace<'tcx> { + /// Return `Some` if this place has no projections -- else return `None`. + /// So for `a` would return `Some`, but for `a.b.c` would return `None`. + pub fn as_base(&self) -> Option<&PlaceBase<'tcx>> { + if !self.elems.is_empty() { + // this is something like `a.b.c` + return None; + } + + Some(&self.base) + } + + /// Return `Some` if this is just a reference to a local variable + /// (e.g., `a`) and `None` if it is something else (e.g., + /// `a.b.c`). + pub fn as_local(&self) -> Option { + match self.as_base()? { + PlaceBase::Local(l) => Some(*l), + _ => None, + } + } + + pub fn into_tree(self) -> NeoPlaceTree<'tcx> { + match self.elems.split_last() { + None => NeoPlaceTree::Base(self.base), + Some((last_element, other_elements)) => { + NeoPlaceTree::Projected(Projection { + base: NeoPlace { base: self.base, elems: other_elements }, + elem: *last_element, + }) + } + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum NeoPlaceTree<'tcx> { + Base(PlaceBase<'tcx>), + Projected(NeoPlaceProjection<'tcx>), +} + +/// Alias for projections as they appear in places, where the base is a place +/// and the index is a local. +pub type NeoPlaceProjection<'tcx> = Projection<'tcx, NeoPlace<'tcx>, Local, Ty<'tcx>>; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn as_new_place(self, place: &Place<'tcx>) -> NeoPlace<'tcx> { @@ -1977,7 +2023,7 @@ impl_stable_hash_for!(struct Static<'tcx> { /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Place`. See the aliases /// `PlaceProjection` etc below. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Projection<'tcx, B, V, T> { pub base: B, pub elem: ProjectionElem<'tcx, V, T>, @@ -3483,7 +3529,7 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx List> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx [PlaceElem<'tcx>] { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); folder.tcx().intern_place_elems(&v) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 258470bf6f860..65b9cc7626c81 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -649,6 +649,17 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx [ProjectionKind<'tcx>] { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_projs(&v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { use ty::InstanceDef::*; From 915d277abae696f462346a8c4e88b299bf1f6a12 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Jan 2019 12:42:37 -0500 Subject: [PATCH 25/34] convert `describe_place` to use `NeoPlace` --- src/librustc/mir/mod.rs | 12 +- src/librustc/mir/tcx.rs | 9 -- .../borrow_check/error_reporting.rs | 122 +++++++++--------- 3 files changed, 69 insertions(+), 74 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f334ef1397b8f..d4609142928ba 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1919,20 +1919,20 @@ pub struct NeoPlace<'tcx> { impl NeoPlace<'tcx> { /// Return `Some` if this place has no projections -- else return `None`. /// So for `a` would return `Some`, but for `a.b.c` would return `None`. - pub fn as_base(&self) -> Option<&PlaceBase<'tcx>> { - if !self.elems.is_empty() { + pub fn as_place_base(&self) -> Option<&PlaceBase<'tcx>>{ + if self.elems.is_empty() { + Some(&self.base) + } else { // this is something like `a.b.c` - return None; + None } - - Some(&self.base) } /// Return `Some` if this is just a reference to a local variable /// (e.g., `a`) and `None` if it is something else (e.g., /// `a.b.c`). pub fn as_local(&self) -> Option { - match self.as_base()? { + match self.as_place_base()? { PlaceBase::Local(l) => Some(*l), _ => None, } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 8413addad1b79..4e5ce3d11defc 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -299,15 +299,6 @@ impl<'tcx> NeoPlace<'tcx> { } } - // Return the base of place without projections - pub fn as_place_base(&self) -> Option<&PlaceBase<'tcx>>{ - if self.elems.is_empty() { - Some(&self.base) - } else { - None - } - } - // for a place_elem returns it's prefix path // Base.[a, b, c] // ^-- place_elem diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index b57594b35350e..b8c1e7f961fe3 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -9,8 +9,9 @@ use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant, ConstraintCategory, Field, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind, - TerminatorKind, VarBindingForm, + TerminatorKind, VarBindingForm, NeoPlace, NeoPlaceTree, PlaceBase, }; +use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, DefIdTree}; use rustc::util::ppaux::RegionHighlightMode; use rustc_data_structures::fx::FxHashSet; @@ -1570,37 +1571,39 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place: &Place<'tcx>, including_downcast: IncludingDowncast, ) -> Option { + let neo_place = self.infcx.tcx.as_new_place(place); let mut buf = String::new(); - match self.append_place_to_string(place, &mut buf, false, &including_downcast) { - Ok(()) => Some(buf), - Err(()) => None, - } + self.append_place_to_string( + &neo_place, + &mut buf, + false, + &including_downcast + ).and(Ok(buf)).ok() } /// Appends end-user visible description of `place` to `buf`. fn append_place_to_string( &self, - place: &Place<'tcx>, + place: &NeoPlace<'tcx>, buf: &mut String, mut autoderef: bool, including_downcast: &IncludingDowncast, ) -> Result<(), ()> { - match *place { - Place::Promoted(_) => { + match place.clone().into_tree() { + NeoPlaceTree::Base(PlaceBase::Promoted(_)) => { buf.push_str("promoted"); } - Place::Local(local) => { + NeoPlaceTree::Base(PlaceBase::Local(local)) => { self.append_local_to_string(local, buf)?; } - Place::Static(ref static_) => { + NeoPlaceTree::Base(PlaceBase::Static(ref static_)) => { buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string()); } - Place::Projection(ref proj) => { + NeoPlaceTree::Projected(proj) => { match proj.elem { ProjectionElem::Deref => { - let neo_place = self.infcx.tcx.as_new_place(place); let upvar_field_projection = - neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + place.is_upvar_field_projection(self.mir, &self.infcx.tcx); if let Some(field) = upvar_field_projection { let var_index = field.index(); let name = self.mir.upvar_decls[var_index].debug_name.to_string(); @@ -1617,7 +1620,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { autoderef, &including_downcast, )?; - } else if let Place::Local(local) = proj.base { + } else if let Some(local) = proj.base.as_local() { if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = self.mir.local_decls[local].is_user_variable { @@ -1660,9 +1663,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } ProjectionElem::Field(field, _ty) => { autoderef = true; - let neo_place = self.infcx.tcx.as_new_place(place); let upvar_field_projection = - neo_place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + place.is_upvar_field_projection(self.mir, &self.infcx.tcx); if let Some(field) = upvar_field_projection { let var_index = field.index(); let name = self.mir.upvar_decls[var_index].debug_name.to_string(); @@ -1727,15 +1729,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, base: &Place, field: Field) -> String { - match *base { - Place::Local(local) => { + fn describe_field(&self, base: &NeoPlace<'tcx>, field: Field) -> String { + match base.clone().into_tree() { + NeoPlaceTree::Base(PlaceBase::Local(local)) => { let local = &self.mir.local_decls[local]; self.describe_field_from_ty(&local.ty, field) } - Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field), - Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field), - Place::Projection(ref proj) => match proj.elem { + NeoPlaceTree::Base(PlaceBase::Promoted(ref prom)) => + self.describe_field_from_ty(&prom.1, field), + NeoPlaceTree::Base(PlaceBase::Static(ref static_)) => + self.describe_field_from_ty(&static_.ty, field), + NeoPlaceTree::Projected(ref proj) => match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field), ProjectionElem::Downcast(def, variant_index) => def.variants[variant_index].fields[field.index()].ident.to_string(), @@ -1796,7 +1800,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// Check if a place is a thread-local static. pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool { - if let Place::Static(statik) = place { + let neo_place = self.infcx.tcx.as_new_place(place); + if let Some(PlaceBase::Static(statik)) = neo_place.as_place_base() { let attrs = self.infcx.tcx.get_attrs(statik.def_id); let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local")); @@ -1813,47 +1818,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> { let tcx = self.infcx.tcx; - match place { - Place::Local(_) | Place::Static(_) | Place::Promoted(_) => { - StorageDeadOrDrop::LocalStorageDead - } - Place::Projection(box PlaceProjection { base, elem }) => { - let base_access = self.classify_drop_access_kind(base); - match elem { - ProjectionElem::Deref => match base_access { - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - assert!( - base.ty(self.mir, tcx).to_ty(tcx).is_box(), - "Drop of value behind a reference or raw pointer" - ); - StorageDeadOrDrop::BoxedStorageDead - } - StorageDeadOrDrop::Destructor(_) => base_access, - }, - ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = base.ty(self.mir, tcx).to_ty(tcx); - match base_ty.sty { - ty::Adt(def, _) if def.has_dtor(tcx) => { - // Report the outermost adt with a destructor - match base_access { - StorageDeadOrDrop::Destructor(_) => base_access, - StorageDeadOrDrop::LocalStorageDead - | StorageDeadOrDrop::BoxedStorageDead => { - StorageDeadOrDrop::Destructor(base_ty) - } + let place = tcx.as_new_place(place); + let mut access = StorageDeadOrDrop::LocalStorageDead; + let mut base_ty = place.base.ty(self.mir); + for elem in place.elems.iter() { + match elem { + ProjectionElem::Deref => match access { + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + assert!( + base_ty.is_box(), + "Drop of value behind a reference or raw pointer" + ); + access = StorageDeadOrDrop::BoxedStorageDead; + } + StorageDeadOrDrop::Destructor(_) => {}, + }, + ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { + match base_ty.sty { + ty::Adt(def, _) if def.has_dtor(tcx) => { + // Report the outermost adt with a destructor + match access { + StorageDeadOrDrop::Destructor(_) => {}, + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + access = StorageDeadOrDrop::Destructor(base_ty); } } - _ => base_access, } + _ => {}, } - - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Index(_) => base_access, } + + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Index(_) => {}, } + base_ty = PlaceTy::from(base_ty).projection_ty(tcx, elem).to_ty(tcx); } + access } /// Annotate argument and return type of function and closure with (synthesized) lifetime for @@ -1897,9 +1900,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "annotate_argument_and_return_for_borrow: reservation={:?}", reservation ); + let reservation = self.infcx.tcx.as_new_place(reservation); // Check that the initial assignment of the reserve location is into a temporary. - let mut target = *match reservation { - Place::Local(local) if self.mir.local_kind(*local) == LocalKind::Temp => local, + let mut target = match reservation.as_local() { + Some(local) if self.mir.local_kind(local) == LocalKind::Temp => local, _ => return None, }; From 62a52ed0f32f575d446b1c939c89abb9dc6109bf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 22 Jan 2019 15:11:14 -0300 Subject: [PATCH 26/34] Implement PlaceExt trait for NeoPlace --- src/librustc_mir/borrow_check/place_ext.rs | 59 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index c55975a1774f7..84df2a02df2f2 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -1,6 +1,6 @@ use rustc::hir; use rustc::mir::ProjectionElem; -use rustc::mir::{Mir, Place, PlaceBase, Mutability}; +use rustc::mir::{Mir, Place, NeoPlace, PlaceBase, Mutability}; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, TyCtxt}; use borrow_check::borrow_set::LocalsStateAtExit; @@ -76,3 +76,60 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { is_unsafe_place } } + +impl<'tcx> PlaceExt<'tcx> for NeoPlace<'tcx> { + fn ignore_borrow( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + mir: &Mir<'tcx>, + locals_state_at_exit: &LocalsStateAtExit, + ) -> bool { + let mut is_unsafe_place = match &self.base { + // If a local variable is immutable, then we only need to track borrows to guard + // against two kinds of errors: + // * The variable being dropped while still borrowed (e.g., because the fn returns + // a reference to a local variable) + // * The variable being moved while still borrowed + // + // In particular, the variable cannot be mutated -- the "access checks" will fail -- + // so we don't have to worry about mutation while borrowed. + PlaceBase::Local(index) => { + match locals_state_at_exit { + LocalsStateAtExit::AllAreInvalidated => false, + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { + let ignore = !has_storage_dead_or_moved.contains(*index) && + mir.local_decls[*index].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", index, ignore); + ignore + } + } + }, + PlaceBase::Promoted(_) => false, + PlaceBase::Static(static_) => { + tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable) + } + }; + + let mut base_ty = self.base.ty(mir); + for elem in self.elems.iter() { + if let ProjectionElem::Deref = elem { + if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = base_ty.sty { + // For both derefs of raw pointers and `&T` + // references, the original path is `Copy` and + // therefore not significant. In particular, + // there is nothing the user can do to the + // original path that would invalidate the + // newly created reference -- and if there + // were, then the user could have copied the + // original path into a new variable and + // borrowed *that* one, leaving the original + // path unborrowed. + is_unsafe_place = true; + } + } + base_ty = PlaceTy::from(base_ty).projection_ty(tcx, elem).to_ty(tcx); + } + + is_unsafe_place + } +} From 7d10e8e221c3d813424b0faab56f20418fd278a5 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 23 Jan 2019 09:14:05 -0300 Subject: [PATCH 27/34] Remove PlaceExt impl for Place and use the NeoPlace one --- src/librustc_mir/borrow_check/borrow_set.rs | 3 +- src/librustc_mir/borrow_check/place_ext.rs | 60 +-------------------- src/librustc_mir/dataflow/impls/borrows.rs | 4 +- 3 files changed, 6 insertions(+), 61 deletions(-) diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 34fa959889937..5ba2dd6f52e51 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -192,7 +192,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { location: mir::Location, ) { if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue { - if borrowed_place.ignore_borrow( + let borrowed_neo_place = self.tcx.as_new_place(borrowed_place); + if borrowed_neo_place.ignore_borrow( self.tcx, self.mir, &self.locals_state_at_exit) { return; } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 84df2a02df2f2..d33dae3bc82e1 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -1,6 +1,6 @@ use rustc::hir; use rustc::mir::ProjectionElem; -use rustc::mir::{Mir, Place, NeoPlace, PlaceBase, Mutability}; +use rustc::mir::{Mir, NeoPlace, PlaceBase, Mutability}; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, TyCtxt}; use borrow_check::borrow_set::LocalsStateAtExit; @@ -19,64 +19,6 @@ crate trait PlaceExt<'tcx> { ) -> bool; } -impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { - fn ignore_borrow( - &self, - tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, - locals_state_at_exit: &LocalsStateAtExit, - ) -> bool { - let neo_place = tcx.as_new_place(self); - let mut is_unsafe_place = match &neo_place.base { - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - PlaceBase::Local(index) => { - match locals_state_at_exit { - LocalsStateAtExit::AllAreInvalidated => false, - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { - let ignore = !has_storage_dead_or_moved.contains(*index) && - mir.local_decls[*index].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", index, ignore); - ignore - } - } - }, - PlaceBase::Promoted(_) => false, - PlaceBase::Static(static_) => { - tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable) - } - }; - - let mut base_ty = neo_place.base.ty(mir); - for elem in neo_place.elems.iter() { - if let ProjectionElem::Deref = elem { - if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = base_ty.sty { - // For both derefs of raw pointers and `&T` - // references, the original path is `Copy` and - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - is_unsafe_place = true; - } - } - base_ty = PlaceTy::from(base_ty).projection_ty(tcx, elem).to_ty(tcx); - } - - is_unsafe_place - } -} - impl<'tcx> PlaceExt<'tcx> for NeoPlace<'tcx> { fn ignore_borrow( &self, diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 5e59e1dc11fee..9cfcca1edd972 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -269,7 +269,9 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { self.kill_borrows_on_place(sets, lhs); if let box mir::Rvalue::Ref(_, _, place) = rhs { - if place.ignore_borrow( + let neo_place = self.tcx.as_new_place(place); + + if neo_place.ignore_borrow( self.tcx, self.mir, &self.borrow_set.locals_state_at_exit, From ed1411c00496352a19fd3af527f65df0388c4df9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 23 Jan 2019 00:10:51 -0300 Subject: [PATCH 28/34] Implement IsPrefixOf trait for NeoPlace --- src/librustc_mir/borrow_check/prefixes.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index c3a8381cd5810..167bab309fc70 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -11,10 +11,10 @@ use super::MirBorrowckCtxt; use rustc::hir; use rustc::ty::{self, TyCtxt}; -use rustc::mir::{Mir, Place, ProjectionElem}; +use rustc::mir::{Mir, Place, NeoPlace, ProjectionElem}; pub trait IsPrefixOf<'tcx> { - fn is_prefix_of(&self, other: &Place<'tcx>) -> bool; + fn is_prefix_of(&self, other: &Self) -> bool; } impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> { @@ -36,6 +36,17 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> { } } +impl<'tcx> IsPrefixOf<'tcx> for NeoPlace<'tcx> { + fn is_prefix_of(&self, other: &NeoPlace<'tcx>) -> bool { + self.base == other.base + && self.elems.len() <= other.elems.len() + && self + .elems + .iter() + .zip(other.elems) + .all(|(elem, other_elem)| elem == other_elem) + } +} pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> { mir: &'cx Mir<'tcx>, From 98a95b81aa1d70d5e4d93c85418033ed86c0af94 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 23 Jan 2019 00:13:49 -0300 Subject: [PATCH 29/34] Remove IsPrefixOf impl for Place and use the NeoPlace one --- .../borrow_check/error_reporting.rs | 4 +++- src/librustc_mir/borrow_check/prefixes.rs | 19 ------------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index b8c1e7f961fe3..ae24ac0fc859b 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -698,7 +698,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // we're not in the uninteresting case where `B` is a // prefix of `D`), then report this as a more interesting // destructor conflict. - if !borrow.borrowed_place.is_prefix_of(place_span.0) { + let borrowed_neo_place = self.infcx.tcx.as_new_place(&borrow.borrowed_place); + let other_neo_place = self.infcx.tcx.as_new_place(place_span.0); + if !borrowed_neo_place.is_prefix_of(&other_neo_place) { self.report_borrow_conflicts_with_destructor( context, borrow, place_span, kind, dropped_ty, ); diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 167bab309fc70..9cfd5203e588b 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -17,25 +17,6 @@ pub trait IsPrefixOf<'tcx> { fn is_prefix_of(&self, other: &Self) -> bool; } -impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> { - fn is_prefix_of(&self, other: &Place<'tcx>) -> bool { - let mut cursor = other; - loop { - if self == cursor { - return true; - } - - match *cursor { - Place::Promoted(_) | - Place::Local(_) | Place::Static(_) => return false, - Place::Projection(ref proj) => { - cursor = &proj.base; - } - } - } - } -} - impl<'tcx> IsPrefixOf<'tcx> for NeoPlace<'tcx> { fn is_prefix_of(&self, other: &NeoPlace<'tcx>) -> bool { self.base == other.base From 42479d325ffd322ffb318e59dc42ea8bd6607313 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 24 Jan 2019 23:38:24 -0300 Subject: [PATCH 30/34] Remove Place::ty and use NeoPlace::ty instead --- src/librustc/mir/tcx.rs | 62 +++---------------- src/librustc_codegen_ssa/mir/analyze.rs | 6 +- src/librustc_codegen_ssa/mir/block.rs | 3 +- src/librustc_codegen_ssa/mir/place.rs | 3 +- .../borrow_check/error_reporting.rs | 20 +++--- src/librustc_mir/borrow_check/mod.rs | 12 ++-- .../borrow_check/mutability_errors.rs | 28 ++++++--- .../borrow_check/nll/type_check/mod.rs | 21 ++++--- src/librustc_mir/borrow_check/prefixes.rs | 3 +- src/librustc_mir/build/block.rs | 3 +- src/librustc_mir/build/matches/mod.rs | 6 +- src/librustc_mir/build/matches/test.rs | 3 +- src/librustc_mir/build/misc.rs | 3 +- .../dataflow/drop_flag_effects.rs | 6 +- .../dataflow/move_paths/builder.rs | 17 ++++- src/librustc_mir/monomorphize/collector.rs | 3 +- .../transform/add_moves_for_packed_drops.rs | 3 +- src/librustc_mir/transform/add_retag.rs | 3 +- src/librustc_mir/transform/check_unsafety.rs | 9 ++- src/librustc_mir/transform/const_prop.rs | 3 +- src/librustc_mir/transform/inline.rs | 6 +- src/librustc_mir/transform/instcombine.rs | 6 +- src/librustc_mir/transform/lower_128bit.rs | 3 +- src/librustc_mir/transform/promote_consts.rs | 3 +- src/librustc_mir/transform/qualify_consts.rs | 21 ++++--- .../transform/uniform_array_move_out.rs | 6 +- src/librustc_mir/util/alignment.rs | 6 +- src/librustc_mir/util/elaborate_drops.rs | 3 +- 28 files changed, 149 insertions(+), 122 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 4e5ce3d11defc..c9ca8b1a8f5cc 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -155,57 +155,6 @@ EnumTypeFoldableImpl! { } } -impl<'tcx> Place<'tcx> { - pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> PlaceTy<'tcx> - where D: HasLocalDecls<'tcx> - { - match *self { - Place::Local(index) => - PlaceTy::Ty { ty: local_decls.local_decls()[index].ty }, - Place::Promoted(ref data) => PlaceTy::Ty { ty: data.1 }, - Place::Static(ref data) => - PlaceTy::Ty { ty: data.ty }, - Place::Projection(ref proj) => - proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), - } - } - - // If this is a field projection, and the field is being projected from a closure type, - // then returns the index of the field being projected. Note that this closure will always - // be `self` in the current MIR, because that is the only time we directly access the fields - // of a closure type. - //pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, - // tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { - // let (place, by_ref) = if let Place::Projection(ref proj) = self { - // if let ProjectionElem::Deref = proj.elem { - // (&proj.base, true) - // } else { - // (self, false) - // } - // } else { - // (self, false) - // }; - - // match place { - // Place::Projection(ref proj) => match proj.elem { - // ProjectionElem::Field(field, _ty) => { - // let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); - - // if (base_ty.is_closure() || base_ty.is_generator()) && - // (!by_ref || mir.upvar_decls[field.index()].by_ref) - // { - // Some(field) - // } else { - // None - // } - // }, - // _ => None, - // } - // _ => None, - // } - //} -} - impl<'tcx> PlaceBase<'tcx> { pub fn ty(&self, local_decls: &impl HasLocalDecls<'tcx>) -> Ty<'tcx> { match self { @@ -376,7 +325,8 @@ impl<'tcx> Rvalue<'tcx> { tcx.mk_array(operand.ty(local_decls, tcx), count) } Rvalue::Ref(reg, bk, ref place) => { - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let place_ty = neo_place.ty(local_decls, tcx).to_ty(tcx); tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, @@ -402,7 +352,8 @@ impl<'tcx> Rvalue<'tcx> { operand.ty(local_decls, tcx) } Rvalue::Discriminant(ref place) => { - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let ty = neo_place.ty(local_decls, tcx).to_ty(tcx); if let ty::Adt(adt_def, _) = ty.sty { adt_def.repr.discr_type().to_ty(tcx) } else { @@ -451,7 +402,10 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | - &Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx), + &Operand::Move(ref l) => { + let neo_place = tcx.as_new_place(l); + neo_place.ty(local_decls, tcx).to_ty(tcx) + } &Operand::Constant(ref c) => c.ty, } } diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index f3475d1c48968..a1230982913b3 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -166,7 +166,8 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> _ => false }; if is_consume { - let base_ty = proj.base.ty(self.fx.mir, cx.tcx()); + let neo_base = cx.tcx().as_new_place(&proj.base); + let base_ty = neo_base.ty(self.fx.mir, cx.tcx()); let base_ty = self.fx.monomorphize(&base_ty); // ZSTs don't require any actual memory access. @@ -245,7 +246,8 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> } PlaceContext::MutatingUse(MutatingUseContext::Drop) => { - let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx()); + let neo_place = self.fx.cx.tcx().as_new_place(&mir::Place::Local(local)); + let ty = neo_place.ty(self.fx.mir, self.fx.cx.tcx()); let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx())); // Only need the place if we're actually dropping it. diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index aa82c853257a3..90f8d0ff17ebc 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -287,7 +287,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Drop { ref location, target, unwind } => { - let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); + let neo_location = bx.tcx().as_new_place(location); + let ty = neo_location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); let ty = self.monomorphize(&ty); let drop_fn = monomorphize::resolve_drop_in_place(bx.tcx(), ty); diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index b10611e5ac797..450d999d9bba2 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -490,7 +490,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); - let place_ty = place.ty(self.mir, tcx); + let neo_place = tcx.as_new_place(place); + let place_ty = neo_place.ty(self.mir, tcx); self.monomorphize(&place_ty.to_ty(tcx)) } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index ae24ac0fc859b..4efe0ecc7dbd5 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -182,7 +182,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); } - let ty = used_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let neo_place = self.infcx.tcx.as_new_place(used_place); + let ty = neo_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); let needs_note = match ty.sty { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck_tables_of(id); @@ -197,11 +198,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if needs_note { let mpi = self.move_data.moves[move_out_indices[0]].path; let place = &self.move_data.move_paths[mpi].place; + let neo_place = self.infcx.tcx.as_new_place(place); - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - let opt_name = self.describe_place_with_options(place, IncludingDowncast(true)); - let note_msg = match opt_name { - Some(ref name) => format!("`{}`", name), + let ty = neo_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let note_msg = match self.describe_place_with_options( + place, + IncludingDowncast(true), + ) { + Some(name) => format!("`{}`", name), None => "value".to_owned(), }; if let ty::TyKind::Param(param_ty) = ty.sty { @@ -574,7 +578,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Define a small closure that we can use to check if the type of a place // is a union. let is_union = |place: &Place<'tcx>| -> bool { - place.ty(self.mir, self.infcx.tcx) + let neo_place = self.infcx.tcx.as_new_place(place); + neo_place.ty(self.mir, self.infcx.tcx) .to_ty(self.infcx.tcx) .ty_adt_def() .map(|adt| adt.is_union()) @@ -624,7 +629,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Also compute the name of the union type, eg. `Foo` so we // can add a helpful note with it. - let ty = base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let neo_base = self.infcx.tcx.as_new_place(base); + let ty = neo_base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); return Some((desc_base, desc_first, desc_second, ty.to_string())); }, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d8b9d0cf7e4ff..433cb1dc0d5e9 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -629,7 +629,8 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx let gcx = self.infcx.tcx.global_tcx(); // Compute the type with accurate region information. - let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx); + let neo_drop_place = self.infcx.tcx.as_new_place(drop_place); + let drop_place_ty = neo_drop_place.ty(self.mir, self.infcx.tcx); // Erase the regions. let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty) @@ -1661,7 +1662,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - match base.ty(self.mir, tcx).to_ty(tcx).sty { + let neo_base = tcx.as_new_place(base); + match neo_base.ty(self.mir, tcx).to_ty(tcx).sty { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( context, InitializationRequiringAction::Assignment, @@ -1766,7 +1768,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty { + let neo_base = tcx.as_new_place(base); + if let ty::TyKind::Adt(def, _) = neo_base.ty(this.mir, tcx).to_ty(tcx).sty { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of( @@ -2032,7 +2035,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { - let base_ty = proj.base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let neo_base = self.infcx.tcx.as_new_place(&proj.base); + let base_ty = neo_base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); // Check the kind of deref to decide match base_ty.sty { diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index fd41370ed4f88..0a51307127a07 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -61,8 +61,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Field(upvar_index, _), }) => { + let neo_base = self.infcx.tcx.as_new_place(base); debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + neo_base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) )); item_msg = format!("`{}`", access_place_desc.unwrap()); @@ -82,8 +83,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { if *base == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); + let neo_the_place_err = self.infcx.tcx.as_new_place(the_place_err); debug_assert!(is_closure_or_generator( - the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + neo_the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) )); let neo_place = self.infcx.tcx.as_new_place(access_place); reason = if neo_place.is_upvar_field_projection(self.mir, @@ -107,12 +109,16 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { item_msg = format!("`{}`", access_place_desc.unwrap()); reason = ", as it is immutable for the pattern guard".to_string(); } else { - let pointer_type = - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_region_ptr() { - "`&` reference" - } else { - "`*const` pointer" - }; + let neo_base = self.infcx.tcx.as_new_place(base); + let pointer_type = if neo_base + .ty(self.mir, self.infcx.tcx) + .to_ty(self.infcx.tcx) + .is_region_ptr() + { + "`&` reference" + } else { + "`*const` pointer" + }; if let Some(desc) = access_place_desc { item_msg = format!("`{}`", desc); reason = match error_access { @@ -227,9 +233,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { }) => { err.span_label(span, format!("cannot {ACT}", ACT = act)); + let neo_base = self.infcx.tcx.as_new_place(base); if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), + neo_base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), field, ) { err.span_suggestion( @@ -299,8 +306,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Field(upvar_index, _), }) => { + let neo_base = self.infcx.tcx.as_new_place(base); debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + neo_base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) )); err.span_label(span, format!("cannot {ACT}", ACT = act)); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ed8859d7964a7..a553bf1cd2225 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -553,7 +553,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } ProjectionElem::Index(i) => { - let index_ty = Place::Local(i).ty(self.mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(&Place::Local(i)); + let index_ty = neo_place.ty(self.mir, tcx).to_ty(tcx); if index_ty != tcx.types.usize { PlaceTy::Ty { ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), @@ -1257,7 +1258,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { _ => ConstraintCategory::Assignment, }; - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let place_ty = neo_place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) @@ -1309,7 +1311,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ref place, variant_index, } => { - let place_type = place.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let place_type = neo_place.ty(mir, tcx).to_ty(tcx); let adt = match place_type.sty { TyKind::Adt(adt, _) if adt.is_enum() => adt, _ => { @@ -1331,7 +1334,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; } StatementKind::AscribeUserType(ref place, variance, box ref projection) => { - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let place_ty = neo_place.ty(mir, tcx).to_ty(tcx); if let Err(terr) = self.relate_type_and_user_type( place_ty, variance, @@ -1387,7 +1391,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { target: _, unwind: _, } => { - let place_ty = location.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(location); + let place_ty = neo_place.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); let locations = term_location.to_locations(); @@ -1535,7 +1540,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let tcx = self.tcx(); match *destination { Some((ref dest, _target_block)) => { - let dest_ty = dest.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(dest); + let dest_ty = neo_place.ty(mir, tcx).to_ty(tcx); let category = match *dest { Place::Local(RETURN_PLACE) => { if let Some(BorrowCheckContext { @@ -2137,7 +2143,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + let neo_base = tcx.as_new_place(base); + let base_ty = neo_base.ty(self.mir, tcx).to_ty(tcx); debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 9cfd5203e588b..653d78152f2af 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -132,7 +132,8 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let neo_base = self.tcx.as_new_place(&proj.base); + let ty = neo_base.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { ty::RawPtr(_) | ty::Ref( diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index f3d89a7a02515..49ed5705dee85 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -165,7 +165,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Then, the block may have an optional trailing expression which is a “return” value // of the block, which is stored into `destination`. let tcx = this.hir.tcx(); - let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(destination); + let destination_ty = neo_place.ty(&this.local_decls, tcx).to_ty(tcx); if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || this.block_context.currently_ignores_tail_results(); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2f1e8c03f2f7e..1815dda5a4b37 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -302,9 +302,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let ty_source_info = self.source_info(user_ty_span); + let neo_place = self.hir.tcx().as_new_place(&place); let user_ty = box pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, - place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + neo_place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), ty_source_info.span, ); self.cfg.push( @@ -1342,9 +1343,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ascription.user_ty, ); + let neo_place = self.hir.tcx().as_new_place(&ascription.source); let user_ty = box ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, - ascription.source.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + neo_place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), source_info.span ); self.cfg.push( diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 696c173b048ad..e0c1f438def36 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -171,10 +171,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { place: &Place<'tcx>, test: &Test<'tcx>) -> Vec { + let neo_place = self.hir.tcx().as_new_place(place); debug!("perform_test({:?}, {:?}: {:?}, {:?})", block, place, - place.ty(&self.local_decls, self.hir.tcx()), + neo_place.ty(&self.local_decls, self.hir.tcx()), test); let source_info = self.source_info(test.span); match test.kind { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index c849c02242840..62ec46bb2eed1 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.hir.tcx(); - let ty = place.ty(&self.local_decls, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(&place); + let ty = neo_place.ty(&self.local_decls, tcx).to_ty(tcx); if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) { Operand::Move(place) } else { diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index 22fb7a3bc470e..3d41f2e6d1756 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -49,7 +49,8 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, place: &mir::Place<'tcx>) -> bool { - let ty = place.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let ty = neo_place.ty(mir, tcx).to_ty(tcx); match ty.sty { ty::Array(..) => { debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", @@ -141,7 +142,8 @@ pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>( { on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { let place = &ctxt.move_data.move_paths[path].place; - let ty = place.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let ty = neo_place.ty(mir, tcx).to_ty(tcx); debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); let gcx = tcx.global_tcx(); diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 1ae050654b4b0..a5e936d4b9e54 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -121,7 +121,8 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let base = self.move_path_for(&proj.base)?; let mir = self.builder.mir; let tcx = self.builder.tcx; - let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(&proj.base); + let place_ty = neo_place.ty(mir, tcx).to_ty(tcx); match place_ty.sty { ty::Ref(..) | ty::RawPtr(..) => return Err(MoveError::cannot_move_out_of( @@ -425,10 +426,20 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { Place::Projection(box Projection { base, elem: ProjectionElem::Field(_, _), - }) if match base.ty(self.builder.mir, self.builder.tcx).to_ty(self.builder.tcx).sty { + }) if { + let neo_place = self.builder.tcx.as_new_place(base); + match neo_place + .ty(self.builder.mir, self.builder.tcx) + .to_ty(self.builder.tcx) + .sty + { ty::TyKind::Adt(def, _) if def.is_union() => true, _ => false, - } => base, + } + } => + { + base + } // Otherwise, lookup the place. _ => place, }; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index bc63f8b6ac854..1194bf405b4b8 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -608,7 +608,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.mir, self.tcx) + let neo_location = self.tcx.as_new_place(location); + let ty = neo_location.ty(self.mir, self.tcx) .to_ty(self.tcx); let ty = tcx.subst_and_normalize_erasing_regions( self.param_substs, diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index 8ec6902cf15fd..2a78dfe473ddd 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -106,7 +106,8 @@ fn add_move_for_packed_drop<'a, 'tcx>( }; let source_info = terminator.source_info; - let ty = location.ty(mir, tcx).to_ty(tcx); + let neo_location = tcx.as_new_place(location); + let ty = neo_location.ty(mir, tcx).to_ty(tcx); let temp = patch.new_temp(ty, terminator.source_info.span); let storage_dead_block = patch.new_block(BasicBlockData { diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 3d5897bca9f52..8726829fdf77c 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -88,7 +88,8 @@ impl MirPass for AddRetag { let needs_retag = |place: &Place<'tcx>| { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. - is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx) + let neo_place = tcx.as_new_place(&place); + is_stable(place) && may_have_reference(neo_place.ty(&*local_decls, tcx).to_ty(tcx), tcx) }; // PART 1 diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index ab8da2f352c1c..a1efb7c51e5c8 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -226,7 +226,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { }], &[]); } } - let is_borrow_of_interior_mut = context.is_borrow() && !base + let neo_base = self.tcx.as_new_place(base); + let is_borrow_of_interior_mut = context.is_borrow() && !neo_base .ty(self.mir, self.tcx) .to_ty(self.tcx) .is_freeze(self.tcx, self.param_env, self.source_info.span); @@ -250,7 +251,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.source_info = self.mir.local_decls[local].source_info; } } - let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); + let neo_base = self.tcx.as_new_place(base); + let base_ty = neo_base.ty(self.mir, self.tcx).to_ty(self.tcx); match base_ty.sty { ty::RawPtr(..) => { self.require_unsafe("dereference of raw pointer", @@ -419,7 +421,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { }) = place { match *elem { ProjectionElem::Field(..) => { - let ty = base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + let neo_base = self.tcx.as_new_place(base); + let ty = neo_base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); match ty.sty { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index dc556a15cd855..b63d1f4cc335c 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -553,7 +553,8 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { ) { trace!("visit_statement: {:?}", statement); if let StatementKind::Assign(ref place, ref rval) = statement.kind { - let place_ty: ty::Ty<'tcx> = place + let neo_place = self.tcx.as_new_place(place); + let place_ty: ty::Ty<'tcx> = neo_place .ty(&self.mir.local_decls, self.tcx) .to_ty(self.tcx); if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 9f0907adc9892..b5b950fba0297 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -305,7 +305,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { work_list.push(target); // If the location doesn't actually need dropping, treat it like // a regular goto. - let ty = location.ty(callee_mir, tcx).subst(tcx, callsite.substs); + let neo_location = tcx.as_new_place(location); + let ty = neo_location.ty(callee_mir, tcx).subst(tcx, callsite.substs); let ty = ty.to_ty(tcx); if ty.needs_drop(tcx, param_env) { cost += CALL_PENALTY; @@ -549,7 +550,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { assert!(args.next().is_none()); let tuple = Place::Local(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty { + let neo_tuple = tcx.as_new_place(&tuple); + let tuple_tys = if let ty::Tuple(s) = neo_tuple.ty(caller_mir, tcx).to_ty(tcx).sty { s } else { bug!("Closure arguments are not passed as a tuple"); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 2b5e761d1d055..6494a08ef62e5 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -82,14 +82,16 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { if let ProjectionElem::Deref = projection.elem { - if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + let neo_base = self.tcx.as_new_place(&projection.base); + if neo_base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { self.optimizations.and_stars.insert(location); } } } if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + let neo_place = self.tcx.as_new_place(place); + let place_ty = neo_place.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); if let TyKind::Array(_, len) = place_ty.sty { let span = self.mir.source_info(location).span; let ty = self.tcx.types.usize; diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index d14e0f078e6c6..a1a26fecb9d0a 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -136,7 +136,8 @@ fn check_lang_item_type<'a, 'tcx, D>( let sig = poly_sig.no_bound_vars().unwrap(); let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let place_ty = neo_place.ty(local_decls, tcx).to_ty(tcx); let expected = [lhs_ty, rhs_ty, place_ty]; assert_eq!(sig.inputs_and_output[..], expected, "lang item {}", tcx.def_symbol_name(did)); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 1602fc35a2c95..f2bc9025670c9 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -306,7 +306,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { place = &mut proj.base; }; - let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx); + let neo_place = self.tcx.as_new_place(place); + let ty = neo_place.ty(local_decls, self.tcx).to_ty(self.tcx); let span = statement.source_info.span; Operand::Move(mem::replace(place, promoted_place(ty, span))) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2d941902debc3..2e55dce4ea93c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -449,7 +449,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // just make sure this doesn't get promoted this.add(Qualif::NOT_CONST); } - let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); + let neo_base = this.tcx.as_new_place(&proj.base); + let base_ty = neo_base.ty(this.mir, this.tcx).to_ty(this.tcx); match this.mode { Mode::Fn => {}, _ => { @@ -473,7 +474,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { ProjectionElem::Subslice {..} | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); + let neo_base = this.tcx.as_new_place(&proj.base); + let base_ty = neo_base.ty(this.mir, this.tcx).to_ty(this.tcx); if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { match this.mode { @@ -496,7 +498,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - let ty = place.ty(this.mir, this.tcx).to_ty(this.tcx); + let neo_place = this.tcx.as_new_place(place); + let ty = neo_place.ty(this.mir, this.tcx).to_ty(this.tcx); this.qualif.restrict(ty, this.tcx, this.param_env); } @@ -551,7 +554,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { let mut is_reborrow = false; if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let neo_base = self.tcx.as_new_place(&proj.base); + let base_ty = neo_base.ty(self.mir, self.tcx).to_ty(self.tcx); if let ty::Ref(..) = base_ty.sty { is_reborrow = true; } @@ -592,7 +596,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Rvalue::Len(_) => {} Rvalue::Ref(_, kind, ref place) => { - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + let neo_place = self.tcx.as_new_place(place); + let ty = neo_place.ty(self.mir, self.tcx).to_ty(self.tcx); // Default to forbidding the borrow and/or its promotion, // due to the potential for direct or interior mutability, @@ -1015,7 +1020,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } else { // Be conservative about the returned value of a const fn. let tcx = self.tcx; - let ty = dest.ty(self.mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(dest); + let ty = neo_place.ty(self.mir, tcx).to_ty(tcx); if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn { self.qualif = Qualif::NOT_PROMOTABLE; } else { @@ -1044,7 +1050,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if let Some(span) = needs_drop { // Double-check the type being dropped, to minimize false positives. - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + let neo_place = self.tcx.as_new_place(place); + let ty = neo_place.ty(self.mir, self.tcx).to_ty(self.tcx); if ty.needs_drop(self.tcx, self.param_env) { struct_span_err!(self.tcx.sess, span, E0493, "destructors cannot be evaluated at compile-time") diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 5ab9669baaca0..20eeb6eb236f9 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -69,7 +69,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { from_end: false} = proj.elem { // no need to transformation } else { - let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let neo_base = self.tcx.as_new_place(&proj.base); + let place_ty = neo_base.ty(self.mir, self.tcx).to_ty(self.tcx); if let ty::Array(item_ty, const_size) = place_ty.sty { if let Some(size) = const_size.assert_usize(self.tcx) { assert!(size <= u32::max_value() as u64, @@ -191,7 +192,8 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); let opt_size = opt_src_place.and_then(|src_place| { - let src_ty = src_place.ty(mir, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(src_place); + let src_ty = neo_place.ty(mir, tcx).to_ty(tcx); if let ty::Array(_, ref size_o) = src_ty.sty { size_o.assert_usize(tcx) } else { diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 659b5beb30588..c8b9d77253707 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -17,7 +17,8 @@ pub fn is_disaligned<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return false } - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let neo_place = tcx.as_new_place(place); + let ty = neo_place.ty(local_decls, tcx).to_ty(tcx); match tcx.layout_raw(param_env.and(ty)) { Ok(layout) if layout.align.abi.bytes() == 1 => { // if the alignment is 1, the type can't be further @@ -46,7 +47,8 @@ fn is_within_packed<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = base.ty(local_decls, tcx).to_ty(tcx); + let neo_base = tcx.as_new_place(base); + let ty = neo_base.ty(local_decls, tcx).to_ty(tcx); match ty.sty { ty::Adt(def, _) if def.repr.packed() => { return true diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 8b55a4424ae29..355467f9e73be 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -122,7 +122,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx> { fn place_ty(&self, place: &Place<'tcx>) -> Ty<'tcx> { - place.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx()) + let neo_place = self.tcx().as_new_place(place); + neo_place.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx()) } fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { From 66a18004d6478f99a3c3114b43e46d4db5e4dd03 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 27 Jan 2019 16:02:37 +0100 Subject: [PATCH 31/34] Remove Place::local & Place::base_local and use NeoPlace::base_local instead --- src/librustc/mir/mod.rs | 33 +++++----------- .../borrow_check/error_reporting.rs | 38 +++++++++++++------ src/librustc_mir/borrow_check/mod.rs | 6 ++- src/librustc_mir/borrow_check/used_muts.rs | 6 ++- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d4609142928ba..a74ca7a98ed36 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2110,30 +2110,6 @@ impl<'tcx> Place<'tcx> { pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { Place::Projection(Box::new(PlaceProjection { base: self, elem })) } - - /// Find the innermost `Local` from this `Place`, *if* it is either a local itself or - /// a single deref of a local. - /// - /// FIXME: can we safely swap the semantics of `fn base_local` below in here instead? - pub fn local(&self) -> Option { - match self { - Place::Local(local) | - Place::Projection(box Projection { - base: Place::Local(local), - elem: ProjectionElem::Deref, - }) => Some(*local), - _ => None, - } - } - - /// Find the innermost `Local` from this `Place`. - pub fn base_local(&self) -> Option { - match self { - Place::Local(local) => Some(*local), - Place::Projection(box Projection { base, elem: _ }) => base.base_local(), - Place::Promoted(..) | Place::Static(..) => None, - } - } } impl<'tcx> NeoPlace<'tcx> { @@ -2184,6 +2160,15 @@ impl<'tcx> NeoPlace<'tcx> { self.elem(tcx, ProjectionElem::Index(index)) } + /// Find the innermost `Local` from this `Place`. + pub fn base_local(&self) -> Option { + if let PlaceBase::Local(local) = self.base { + Some(local) + } else { + None + } + } + pub fn constant_index( self, tcx: TyCtxt<'_, '_, 'tcx>, diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 4efe0ecc7dbd5..2c59889e5f9b0 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -579,7 +579,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // is a union. let is_union = |place: &Place<'tcx>| -> bool { let neo_place = self.infcx.tcx.as_new_place(place); - neo_place.ty(self.mir, self.infcx.tcx) + neo_place + .ty(self.mir, self.infcx.tcx) .to_ty(self.infcx.tcx) .ty_adt_def() .map(|adt| adt.is_union()) @@ -1481,15 +1482,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { diag: &mut DiagnosticBuilder<'_>, ) { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); - let mut target = place.local(); + let neo_place = self.infcx.tcx.as_new_place(place); + let mut target = neo_place.base_local(); for stmt in &self.mir[location.block].statements[location.statement_index..] { debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind { debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); match from { - Operand::Copy(ref place) | - Operand::Move(ref place) if target == place.local() => - target = into.local(), + Operand::Copy(ref place) | Operand::Move(ref place) + if { + let neo_place = self.infcx.tcx.as_new_place(place); + target == neo_place.base_local() + } => + { + let neo_into = self.infcx.tcx.as_new_place(into); + target = neo_into.base_local(); + } _ => {}, } } @@ -1512,9 +1520,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { debug!("add_moved_or_invoked_closure_note: id={:?}", id); if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { - Some(Operand::Copy(ref place)) | - Some(Operand::Move(ref place)) if target == place.local() => - place.local().unwrap(), + Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place)) + if { + let neo_place = self.infcx.tcx.as_new_place(place); + target == neo_place.base_local() + } => + { + neo_place.base_local().unwrap() + } _ => return, }; @@ -1949,7 +1962,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); // Find the local from the operand. - let assigned_from_local = match assigned_from.local() { + let neo_assigned_from = self.infcx.tcx.as_new_place(assigned_from); + let assigned_from_local = match neo_assigned_from.base_local() { Some(local) => local, None => continue, }; @@ -2005,7 +2019,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); // Find the local from the rvalue. - let assigned_from_local = match assigned_from.local() { + let neo_assigned_from = self.infcx.tcx.as_new_place(assigned_from); + let assigned_from_local = match neo_assigned_from.base_local() { Some(local) => local, None => continue, }; @@ -2068,7 +2083,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { assigned_from, ); - if let Some(assigned_from_local) = assigned_from.local() { + let neo_assigned_from = self.infcx.tcx.as_new_place(assigned_from); + if let Some(assigned_from_local) = neo_assigned_from.base_local() { debug!( "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", assigned_from_local, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 433cb1dc0d5e9..f2a1fe45c77c1 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1680,7 +1680,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { check_parent_of_field(self, context, base, span, flow_state); - if let Some(local) = place.base_local() { + let neo_place = tcx.as_new_place(place); + if let Some(local) = neo_place.base_local() { // rust-lang/rust#21232, // #54499, #54986: during // period where we reject @@ -1814,7 +1815,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // partial initialization, do not complain about mutability // errors except for actual mutation (as opposed to an attempt // to do a partial initialization). - let previously_initialized = if let Some(local) = place.base_local() { + let neo_place = self.infcx.tcx.as_new_place(place); + let previously_initialized = if let Some(local) = neo_place.base_local() { self.is_local_ever_initialized(local, flow_state).is_some() } else { true diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 6f338158af3bd..c43e80749d6b5 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -61,7 +61,8 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c debug!("visit_terminator_kind: kind={:?}", kind); match &kind { TerminatorKind::Call { destination: Some((into, _)), .. } => { - if let Some(local) = into.base_local() { + let neo_into = self.mbcx.infcx.tcx.as_new_place(into); + if let Some(local) = neo_into.base_local() { debug!( "visit_terminator_kind: kind={:?} local={:?} \ never_initialized_mut_locals={:?}", @@ -87,7 +88,8 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c // be those that were never initialized - we will consider those as being used as // they will either have been removed by unreachable code optimizations; or linted // as unused variables. - if let Some(local) = into.base_local() { + let neo_into = self.mbcx.infcx.tcx.as_new_place(into); + if let Some(local) = neo_into.base_local() { debug!( "visit_statement: statement={:?} local={:?} \ never_initialized_mut_locals={:?}", From c278ff91c2e4d94edd076fdface523ff333f19ca Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 29 Jan 2019 22:49:32 +0100 Subject: [PATCH 32/34] Make into_tree generate Place instead of PlaceTree --- src/librustc/mir/mod.rs | 23 ++++---- .../borrow_check/error_reporting.rs | 52 +++++++++++-------- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a74ca7a98ed36..f93784c1bd044 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1938,16 +1938,21 @@ impl NeoPlace<'tcx> { } } - pub fn into_tree(self) -> NeoPlaceTree<'tcx> { - match self.elems.split_last() { - None => NeoPlaceTree::Base(self.base), - Some((last_element, other_elements)) => { - NeoPlaceTree::Projected(Projection { - base: NeoPlace { base: self.base, elems: other_elements }, - elem: *last_element, - }) - } + pub fn into_tree(self) -> Place<'tcx> { + let mut result = match self.base { + PlaceBase::Local(local) => { Place::Local(local) } + PlaceBase::Static(_static) => { Place::Static(_static) } + PlaceBase::Promoted(promoted) => { Place::Promoted(promoted) } + }; + + for elem in self.elems { + result = Place::Projection(Box::new(Projection { + base: result, + elem: *elem + })); } + + result } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 2c59889e5f9b0..a4b72b494b851 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -9,7 +9,7 @@ use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant, ConstraintCategory, Field, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind, - TerminatorKind, VarBindingForm, NeoPlace, NeoPlaceTree, PlaceBase, + TerminatorKind, VarBindingForm, NeoPlace, PlaceBase, }; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, DefIdTree}; @@ -1611,16 +1611,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { including_downcast: &IncludingDowncast, ) -> Result<(), ()> { match place.clone().into_tree() { - NeoPlaceTree::Base(PlaceBase::Promoted(_)) => { + Place::Promoted(_) => { buf.push_str("promoted"); } - NeoPlaceTree::Base(PlaceBase::Local(local)) => { + Place::Local(local) => { self.append_local_to_string(local, buf)?; } - NeoPlaceTree::Base(PlaceBase::Static(ref static_)) => { + Place::Static(ref static_) => { buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string()); } - NeoPlaceTree::Projected(proj) => { + Place::Projection(proj) => { match proj.elem { ProjectionElem::Deref => { let upvar_field_projection = @@ -1634,19 +1634,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { buf.push_str(&format!("*{}", &name)); } } else { + let neo_place = self.infcx.tcx.as_new_place(&proj.base); + if autoderef { self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, )?; - } else if let Some(local) = proj.base.as_local() { + } else if let Some(local) = neo_place.as_local() { if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = self.mir.local_decls[local].is_user_variable { self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1654,7 +1656,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } else { buf.push_str(&"*"); self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1663,7 +1665,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } else { buf.push_str(&"*"); self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1672,8 +1674,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } ProjectionElem::Downcast(..) => { + let neo_place = self.infcx.tcx.as_new_place(&proj.base); self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1691,9 +1694,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let name = self.mir.upvar_decls[var_index].debug_name.to_string(); buf.push_str(&name); } else { - let field_name = self.describe_field(&proj.base, field); + let neo_place = self.infcx.tcx.as_new_place(&proj.base); + let field_name = self.describe_field(&neo_place, field); self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1704,8 +1708,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ProjectionElem::Index(index) => { autoderef = true; + let neo_place = self.infcx.tcx.as_new_place(&proj.base); self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1718,11 +1723,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; + let neo_place = self.infcx.tcx.as_new_place(&proj.base); // Since it isn't possible to borrow an element on a particular index and // then use another while the borrow is held, don't output indices details // to avoid confusing the end-user self.append_place_to_string( - &proj.base, + &neo_place, buf, autoderef, &including_downcast, @@ -1752,16 +1758,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// End-user visible description of the `field`nth field of `base` fn describe_field(&self, base: &NeoPlace<'tcx>, field: Field) -> String { match base.clone().into_tree() { - NeoPlaceTree::Base(PlaceBase::Local(local)) => { + Place::Local(local) => { let local = &self.mir.local_decls[local]; self.describe_field_from_ty(&local.ty, field) } - NeoPlaceTree::Base(PlaceBase::Promoted(ref prom)) => + Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field), - NeoPlaceTree::Base(PlaceBase::Static(ref static_)) => + Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field), - NeoPlaceTree::Projected(ref proj) => match proj.elem { - ProjectionElem::Deref => self.describe_field(&proj.base, field), + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Deref => { + let neo_place = self.infcx.tcx.as_new_place(&proj.base); + self.describe_field(&neo_place, field) + } ProjectionElem::Downcast(def, variant_index) => def.variants[variant_index].fields[field.index()].ident.to_string(), ProjectionElem::Field(_, field_type) => { @@ -1770,7 +1779,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - self.describe_field(&proj.base, field) + let neo_place = self.infcx.tcx.as_new_place(&proj.base); + self.describe_field(&neo_place, field) } }, } From cf4da24aa9dc93c99d175b9e7a3456b3cec5a166 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 30 Jan 2019 16:55:37 -0500 Subject: [PATCH 33/34] implement `RustcDecodable` for `NeoPlace` --- src/librustc/mir/mod.rs | 5 ++--- src/librustc/ty/codec.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index f93784c1bd044..58edc2268b21b 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1907,14 +1907,13 @@ pub enum Place<'tcx> { } /// A new Place repr -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable)] pub struct NeoPlace<'tcx> { pub base: PlaceBase<'tcx>, pub elems: &'tcx [PlaceElem<'tcx>], } -// FIXME -// impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List> {} +impl serialize::UseSpecializedDecodable for NeoPlace<'tcx> {} impl NeoPlace<'tcx> { /// Return `Some` if this place has no projections -- else return `None`. diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index e0e4d9c362a6c..ebfe80876fa31 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -14,6 +14,7 @@ use std::hash::Hash; use std::intrinsics; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; +use mir; use mir::interpret::Allocation; /// The shorthand encoding uses an enum's variant index `usize` @@ -264,6 +265,20 @@ pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D) Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) } +#[inline] +pub fn decode_neo_place<'a, 'tcx, D>(decoder: &mut D) + -> Result, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + let base: mir::PlaceBase<'tcx> = Decodable::decode(decoder)?; + let len = decoder.read_usize()?; + let interned: Vec> = (0..len).map(|_| Decodable::decode(decoder)) + .collect::>()?; + let elems: &'tcx [mir::PlaceElem<'tcx>] = decoder.tcx().mk_place_elems(interned.into_iter()); + Ok(mir::NeoPlace { base, elems }) +} + #[macro_export] macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { @@ -404,6 +419,15 @@ macro_rules! implement_ty_decoder { decode_allocation(self) } } + + impl<$($typaram),*> SpecializedDecoder<$crate::mir::NeoPlace<'tcx>> + for $DecoderName<$($typaram),*> { + fn specialized_decode( + &mut self + ) -> Result<$crate::mir::NeoPlace<'tcx>, Self::Error> { + decode_neo_place(self) + } + } } } } From 222abfc311b7342c3d215bd8ba99fc8745c27afa Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 1 Feb 2019 23:56:31 +0100 Subject: [PATCH 34/34] Make StatementKind::Assign carry a NeoPlace instead of a Place --- src/librustc/mir/mod.rs | 2 +- src/librustc/mir/visit.rs | 28 +++++--- src/librustc_codegen_ssa/mir/analyze.rs | 6 +- src/librustc_codegen_ssa/mir/statement.rs | 4 +- src/librustc_mir/borrow_check/borrow_set.rs | 9 ++- .../borrow_check/error_reporting.rs | 15 ++-- src/librustc_mir/borrow_check/mod.rs | 3 +- src/librustc_mir/borrow_check/move_errors.rs | 3 +- .../borrow_check/nll/constraint_generation.rs | 8 +-- .../borrow_check/nll/explain_borrow/mod.rs | 22 ++++-- .../borrow_check/nll/invalidation.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 39 +++++------ src/librustc_mir/borrow_check/used_muts.rs | 3 +- src/librustc_mir/build/block.rs | 3 +- src/librustc_mir/build/cfg.rs | 6 +- src/librustc_mir/build/expr/as_place.rs | 6 +- src/librustc_mir/build/expr/as_rvalue.rs | 22 +++--- src/librustc_mir/build/expr/into.rs | 23 ++++--- src/librustc_mir/build/expr/stmt.rs | 5 +- src/librustc_mir/build/matches/mod.rs | 11 ++- src/librustc_mir/build/matches/test.rs | 25 ++++--- src/librustc_mir/build/misc.rs | 3 +- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- .../dataflow/move_paths/builder.rs | 7 +- src/librustc_mir/interpret/step.rs | 3 +- src/librustc_mir/shim.rs | 23 ++++--- .../transform/add_moves_for_packed_drops.rs | 2 +- src/librustc_mir/transform/add_retag.rs | 5 +- .../transform/cleanup_post_borrowck.rs | 7 +- src/librustc_mir/transform/const_prop.rs | 5 +- src/librustc_mir/transform/copy_prop.rs | 20 ++++-- src/librustc_mir/transform/deaggregator.rs | 3 +- src/librustc_mir/transform/elaborate_drops.rs | 11 ++- src/librustc_mir/transform/generator.rs | 4 +- src/librustc_mir/transform/inline.rs | 8 +-- src/librustc_mir/transform/lower_128bit.rs | 6 +- src/librustc_mir/transform/promote_consts.rs | 13 +++- src/librustc_mir/transform/qualify_consts.rs | 68 ++++++++++++++++++- .../transform/qualify_min_const_fn.rs | 2 +- .../transform/remove_noop_landing_pads.rs | 5 +- src/librustc_mir/transform/rustc_peek.rs | 4 +- .../transform/uniform_array_move_out.rs | 21 +++--- src/librustc_mir/util/elaborate_drops.rs | 40 ++++++----- src/librustc_mir/util/patch.rs | 2 +- 44 files changed, 339 insertions(+), 170 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 58edc2268b21b..429877cf35bbb 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1753,7 +1753,7 @@ impl<'tcx> Statement<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Place. - Assign(Place<'tcx>, Box>), + Assign(NeoPlace<'tcx>, Box>), /// This represents all the reading that a pattern match may do /// (e.g., inspecting constants and discriminant values), and the diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 250625ee0dc8b..e455d9b1f1a46 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -96,7 +96,7 @@ macro_rules! make_mir_visitor { fn visit_assign(&mut self, block: BasicBlock, - place: & $($mutability)* Place<'tcx>, + place: & $($mutability)* NeoPlace<'tcx>, rvalue: & $($mutability)* Rvalue<'tcx>, location: Location) { self.super_assign(block, place, rvalue, location); @@ -441,10 +441,10 @@ macro_rules! make_mir_visitor { fn super_assign(&mut self, _block: BasicBlock, - place: &$($mutability)* Place<'tcx>, + place: &$($mutability)* NeoPlace<'tcx>, rvalue: &$($mutability)* Rvalue<'tcx>, location: Location) { - self.visit_place( + self.visit_neoplace( place, PlaceContext::MutatingUse(MutatingUseContext::Store), location @@ -771,6 +771,16 @@ macro_rules! make_mir_visitor { base, elems, } = place; + + let mut context = context; + + if !elems.is_empty() { + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + } match base { PlaceBase::Local(local) => { @@ -784,13 +794,11 @@ macro_rules! make_mir_visitor { } } - if !elems.is_empty() { - for elem in elems.iter().cloned().rev() { - self.visit_projection_elem( - &$($mutability)* elem.clone(), - location - ); - } + for elem in elems.iter().cloned().rev() { + self.visit_projection_elem( + &$($mutability)* elem.clone(), + location + ); } } diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index a1230982913b3..6235778ff61bf 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -98,18 +98,18 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx, Bx> { fn visit_assign(&mut self, block: mir::BasicBlock, - place: &mir::Place<'tcx>, + place: &mir::NeoPlace<'tcx>, rvalue: &mir::Rvalue<'tcx>, location: Location) { debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue); - if let mir::Place::Local(index) = *place { + if let Some(index) = place.as_local() { self.assign(index, location); if !self.fx.rvalue_creates_operand(rvalue) { self.not_ssa(index); } } else { - self.visit_place( + self.visit_neoplace( place, PlaceContext::MutatingUse(MutatingUseContext::Store), location diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 9561a57d0a7de..c485b4820f271 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -17,7 +17,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(ref place, ref rvalue) => { - if let mir::Place::Local(index) = *place { + if let Some(index) = place.as_local() { match self.locals[index] { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) @@ -43,7 +43,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } else { - let cg_dest = self.codegen_place(&mut bx, place); + let cg_dest = self.codegen_place(&mut bx, &place.clone().into_tree()); self.codegen_rvalue(bx, cg_dest, rvalue) } } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 5ba2dd6f52e51..522e452f53cf9 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -187,7 +187,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { fn visit_assign( &mut self, block: mir::BasicBlock, - assigned_place: &mir::Place<'tcx>, + assigned_place: &mir::NeoPlace<'tcx>, rvalue: &mir::Rvalue<'tcx>, location: mir::Location, ) { @@ -206,15 +206,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { reserve_location: location, activation_location: TwoPhaseActivation::NotTwoPhase, borrowed_place: borrowed_place.clone(), - assigned_place: assigned_place.clone(), + assigned_place: assigned_place.clone().into_tree(), }; let idx = self.idx_vec.push(borrow); self.location_map.insert(location, idx); - self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx); + self.insert_as_pending_if_two_phase(location, &assigned_place.clone().into_tree(), kind, idx); - let neo_place = self.tcx.as_new_place(borrowed_place); - if let mir::PlaceBase::Local(local) = neo_place.base { + if let mir::PlaceBase::Local(local) = borrowed_neo_place.base { self.local_map.entry(local).or_default().insert(idx); } } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index a4b72b494b851..55cdeea2dc1d3 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1495,8 +1495,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { target == neo_place.base_local() } => { - let neo_into = self.infcx.tcx.as_new_place(into); - target = neo_into.base_local(); + target = into.base_local(); } _ => {}, } @@ -1931,7 +1930,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "annotate_argument_and_return_for_borrow: reservation={:?}", reservation ); - let reservation = self.infcx.tcx.as_new_place(reservation); // Check that the initial assignment of the reserve location is into a temporary. let mut target = match reservation.as_local() { Some(local) if self.mir.local_kind(local) == LocalKind::Temp => local, @@ -1946,7 +1944,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", target, stmt ); - if let StatementKind::Assign(Place::Local(assigned_to), box rvalue) = &stmt.kind + if let StatementKind::Assign( + NeoPlace { + base: PlaceBase::Local(assigned_to), + elems: &[], + }, box rvalue) = &stmt.kind { debug!( "annotate_argument_and_return_for_borrow: assigned_to={:?} \ @@ -2513,7 +2515,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .get(location.statement_index) { Some(&Statement { - kind: StatementKind::Assign(Place::Local(local), _), + kind: StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, _), .. }) => local, _ => return OtherUse(use_span), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index f2a1fe45c77c1..c06843fba9123 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -503,9 +503,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx flow_state, ); + let lhs = lhs.clone().into_tree(); self.mutate_place( ContextKind::AssignLhs.new(location), - (lhs, span), + (&lhs, span), Shallow(None), JustWrite, flow_state, diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index a8f05dc41d062..5028c88134d8a 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -118,8 +118,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { .get(location.statement_index) .map(|stmt| &stmt.kind) { - let neo_place = self.infcx.tcx.as_new_place(&place); - if let Some(PlaceBase::Local(local)) = neo_place.as_place_base() { + if let Some(PlaceBase::Local(local)) = place.as_place_base() { let local_decl = &self.mir.local_decls[*local]; // opt_match_place is the // match_span is the span of the expression being matched on diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 588f46cb77fe2..af973100ce4bc 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -6,7 +6,7 @@ use borrow_check::nll::region_infer::values::LivenessValues; use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue}; +use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, NeoPlace, Rvalue}; use rustc::mir::{SourceInfo, Statement, Terminator}; use rustc::mir::UserTypeProjection; use rustc::ty::fold::TypeFoldable; @@ -123,15 +123,15 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx fn visit_assign( &mut self, block: BasicBlock, - place: &Place<'tcx>, + place: &NeoPlace<'tcx>, rvalue: &Rvalue<'tcx>, location: Location, ) { // When we see `X = ...`, then kill borrows of // `(*X).foo` and so forth. if let Some(all_facts) = self.all_facts { - if let Place::Local(temp) = place { - if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) { + if let Some(temp) = place.as_local() { + if let Some(borrow_indices) = self.borrow_set.local_map.get(&temp) { all_facts.killed.reserve(borrow_indices.len()); for &borrow_index in borrow_indices { let location_index = self.location_table.mid_index(location); diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 968c0f53a4852..c51f7ef5fef06 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -6,7 +6,7 @@ use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; use rustc::ty::{self, TyCtxt}; use rustc::mir::{ CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand, - Place, Projection, ProjectionElem, Rvalue, Statement, StatementKind, + Place, NeoPlace, PlaceBase, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind }; use rustc_errors::DiagnosticBuilder; @@ -422,7 +422,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // it which simplifies the termination logic. let mut queue = vec![location]; let mut target = if let Some(&Statement { - kind: StatementKind::Assign(Place::Local(local), _), + kind: StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, _), .. }) = stmt { local @@ -446,11 +449,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { box rvalue, ) = &stmt.kind { let into = match place { - Place::Local(into) => into, - Place::Projection(box Projection { - base: Place::Local(into), - elem: ProjectionElem::Deref, - }) => into, + NeoPlace { + base: PlaceBase::Local(into), + elems: &[], + } => into, + + NeoPlace { + base: PlaceBase::Local(into), + elems, + } if elems.last().unwrap() == &ProjectionElem::Deref => into, + _ => { // Continue at the next location. queue.push(current_location.successor_within_block()); diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 4af004f437fcf..b173b2c619256 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -73,7 +73,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { self.mutate_place( ContextKind::AssignLhs.new(location), - lhs, + &lhs.clone().into_tree(), Shallow(None), JustWrite ); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a553bf1cd2225..3581a71f52c24 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1234,32 +1234,33 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // they are not caused by the user, but rather artifacts // of lowering. Assignments to other sorts of places *are* interesting // though. - let category = match *place { - Place::Local(RETURN_PLACE) => if let Some(BorrowCheckContext { - universal_regions: - UniversalRegions { - defining_ty: DefiningTy::Const(def_id, _), + let category = match place.as_local() { + Some(RETURN_PLACE) => + if let Some(BorrowCheckContext { + universal_regions: + UniversalRegions { + defining_ty: DefiningTy::Const(def_id, _), + .. + }, .. - }, - .. - }) = self.borrowck_context - { - if tcx.is_static(*def_id).is_some() { - ConstraintCategory::UseAsStatic + }) = self.borrowck_context { + if tcx.is_static(*def_id).is_some() { + ConstraintCategory::UseAsStatic + } else { + ConstraintCategory::UseAsConst + } } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return - }, - Place::Local(l) if !mir.local_decls[l].is_user_variable.is_some() => { + ConstraintCategory::Return + }, + + Some(l) if !mir.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } + _ => ConstraintCategory::Assignment, }; - let neo_place = tcx.as_new_place(place); - let place_ty = neo_place.ty(mir, tcx).to_ty(tcx); + let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index c43e80749d6b5..ce39219fdd206 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -88,8 +88,7 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c // be those that were never initialized - we will consider those as being used as // they will either have been removed by unreachable code optimizations; or linted // as unused variables. - let neo_into = self.mbcx.infcx.tcx.as_new_place(into); - if let Some(local) = neo_into.base_local() { + if let Some(local) = into.base_local() { debug!( "visit_statement: statement={:?} local={:?} \ never_initialized_mut_locals={:?}", diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 49ed5705dee85..9aed2f7e72429 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -184,7 +184,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if destination_ty.is_unit() { // We only want to assign an implicit `()` as the return value of the block if the // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.) - this.cfg.push_assign_unit(block, source_info, destination); + let destination = tcx.as_new_place(destination); + this.cfg.push_assign_unit(block, source_info, &destination); } } // Finally, we pop all the let scopes before exiting out from the scope of block diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index a9e468db1d1b7..83a4477b1b6e4 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -33,7 +33,7 @@ impl<'tcx> CFG<'tcx> { pub fn push_assign(&mut self, block: BasicBlock, source_info: SourceInfo, - place: &Place<'tcx>, + place: &NeoPlace<'tcx>, rvalue: Rvalue<'tcx>) { self.push(block, Statement { source_info, @@ -44,7 +44,7 @@ impl<'tcx> CFG<'tcx> { pub fn push_assign_constant(&mut self, block: BasicBlock, source_info: SourceInfo, - temp: &Place<'tcx>, + temp: &NeoPlace<'tcx>, constant: Constant<'tcx>) { self.push_assign(block, source_info, temp, Rvalue::Use(Operand::Constant(box constant))); @@ -53,7 +53,7 @@ impl<'tcx> CFG<'tcx> { pub fn push_assign_unit(&mut self, block: BasicBlock, source_info: SourceInfo, - place: &Place<'tcx>) { + place: &NeoPlace<'tcx>) { self.push_assign(block, source_info, place, Rvalue::Aggregate( box AggregateKind::Tuple, vec![] )); diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 6bd61ab53fd21..960aff3e0b35e 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -86,16 +86,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.temp(usize_ty.clone(), expr_span), this.temp(bool_ty, expr_span), ); + let neo_len = this.hir.tcx().as_new_place(&len); this.cfg.push_assign( block, source_info, // len = len(slice) - &len, + &neo_len, Rvalue::Len(slice.clone()), ); + let neo_lt = this.hir.tcx().as_new_place(<); this.cfg.push_assign( block, source_info, // lt = idx < len - <, + &neo_lt, Rvalue::BinaryOp( BinOp::Lt, Operand::Copy(Place::Local(idx)), diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 3de2f47578650..bec70efe8f0ea 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -90,10 +90,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let minval = this.minval_literal(expr_span, expr.ty); let is_min = this.temp(bool_ty, expr_span); + let neo_is_min = this.hir.tcx().as_new_place(&is_min); this.cfg.push_assign( block, source_info, - &is_min, + &neo_is_min, Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval), ); @@ -135,7 +136,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // malloc some memory of suitable type (thus far, uninitialized): let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg - .push_assign(block, source_info, &Place::Local(result), box_); + .push_assign(block, source_info, &NeoPlace::local(result), box_); // initialize the box contents: unpack!(block = this.into(&Place::Local(result).deref(), block, value)); @@ -414,10 +415,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]); let result_value = self.temp(result_tup, span); + let neo_result_value = self.hir.tcx().as_new_place(&result_value); self.cfg.push_assign( block, source_info, - &result_value, + &neo_result_value, Rvalue::CheckedBinaryOp(op, lhs, rhs), ); let val_fld = Field::new(0); @@ -445,10 +447,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Check for / 0 let is_zero = self.temp(bool_ty, span); let zero = self.zero_literal(span, ty); + let neo_is_zero = self.hir.tcx().as_new_place(&is_zero); self.cfg.push_assign( block, source_info, - &is_zero, + &neo_is_zero, Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero), ); @@ -466,25 +469,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead + let neo_is_neg_1 = self.hir.tcx().as_new_place(&is_neg_1); self.cfg.push_assign( block, source_info, - &is_neg_1, + &neo_is_neg_1, Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1), ); + let neo_is_min = self.hir.tcx().as_new_place(&is_min); self.cfg.push_assign( block, source_info, - &is_min, + &neo_is_min, Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min), ); let is_neg_1 = Operand::Move(is_neg_1); let is_min = Operand::Move(is_min); + let neo_of = self.hir.tcx().as_new_place(&of); self.cfg.push_assign( block, source_info, - &of, + &neo_of, Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min), ); @@ -583,7 +589,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.push_assign( block, source_info, - &Place::Local(temp), + &NeoPlace::local(temp), Rvalue::Ref(this.hir.tcx().types.re_erased, borrow_kind, arg_place), ); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 2ffff68137dd2..e962ff8c6ec43 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -94,8 +94,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { // Body of the `if` expression without an `else` clause must return `()`, thus // we implicitly generate a `else {}` if it is not specified. + let destination = this.hir.tcx().as_new_place(destination); this.cfg - .push_assign_unit(else_block, source_info, destination); + .push_assign_unit(else_block, source_info, &destination); else_block }; @@ -140,10 +141,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); this.cfg.terminate(block, source_info, term); + let destination = this.hir.tcx().as_new_place(destination); this.cfg.push_assign_constant( shortcircuit_block, source_info, - destination, + &destination, Constant { span: expr_span, ty: this.hir.bool_ty(), @@ -164,7 +166,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.cfg.push_assign( else_block, source_info, - destination, + &destination, Rvalue::Use(rhs), ); this.cfg.terminate( @@ -228,8 +230,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // if the test is false, there's no `break` to assign `destination`, so // we have to do it; this overwrites any `break`-assigned value but it's // always `()` anyway + let destination = this.hir.tcx().as_new_place(destination); this.cfg - .push_assign_unit(exit_block, source_info, destination); + .push_assign_unit(exit_block, source_info, &destination); } else { body_block = this.cfg.start_new_block(); let diverge_cleanup = this.diverge_cleanup(); @@ -336,7 +339,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::InlineAsm { .. } | ExprKind::Return { .. } => { unpack!(block = this.stmt_expr(block, expr, None)); - this.cfg.push_assign_unit(block, source_info, destination); + let destination = this.hir.tcx().as_new_place(destination); + this.cfg.push_assign_unit(block, source_info, &destination); block.unit() } @@ -350,8 +354,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); + let destination = this.hir.tcx().as_new_place(destination); this.cfg - .push_assign(block, source_info, destination, rvalue); + .push_assign(block, source_info, &destination, rvalue); block.unit() } ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => { @@ -369,8 +374,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); + let destination = this.hir.tcx().as_new_place(destination); this.cfg - .push_assign(block, source_info, destination, rvalue); + .push_assign(block, source_info, &destination, rvalue); block.unit() } @@ -405,7 +411,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }); let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); - this.cfg.push_assign(block, source_info, destination, rvalue); + let destination = this.hir.tcx().as_new_place(destination); + this.cfg.push_assign(block, source_info, &destination, rvalue); block.unit() } }; diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 1cbc60586c356..b24c4d8d432c8 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -54,6 +54,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); + let lhs = this.hir.tcx().as_new_place(&lhs); this.cfg.push_assign(block, source_info, &lhs, rhs); } @@ -92,6 +93,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { rhs ) ); + let lhs = this.hir.tcx().as_new_place(&lhs); this.cfg.push_assign(block, source_info, &lhs, result); this.block_context.pop(); @@ -129,6 +131,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = this.into(&destination, block, value)); this.block_context.pop(); } else { + let destination = this.hir.tcx().as_new_place(&destination); this.cfg.push_assign_unit(block, source_info, &destination) } this.exit_scope(expr_span, (region_scope, source_info), block, break_block); @@ -145,7 +148,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } None => { this.cfg - .push_assign_unit(block, source_info, &Place::Local(RETURN_PLACE)); + .push_assign_unit(block, source_info, &NeoPlace::local(RETURN_PLACE)); block } }; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 1815dda5a4b37..3fa66761578cb 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -1396,8 +1396,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match binding.binding_mode { BindingMode::ByValue => { let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source.clone()); + let neo_ref_for_guard = self.hir.tcx().as_new_place(&ref_for_guard); self.cfg - .push_assign(block, source_info, &ref_for_guard, rvalue); + .push_assign(block, source_info, &neo_ref_for_guard, rvalue); } BindingMode::ByRef(borrow_kind) => { // Tricky business: For `ref id` and `ref mut id` @@ -1440,9 +1441,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }, }; let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source.clone()); + let neo_val_for_guard = self.hir.tcx().as_new_place(&val_for_guard); self.cfg - .push_assign(block, source_info, &val_for_guard, rvalue); + .push_assign(block, source_info, &neo_val_for_guard, rvalue); let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, val_for_guard); + let ref_for_guard = self.hir.tcx().as_new_place(&ref_for_guard); self.cfg .push_assign(block, source_info, &ref_for_guard, rvalue); } @@ -1476,6 +1479,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Rvalue::Ref(re_erased, borrow_kind, binding.source.clone()) } }; + let local = self.hir.tcx().as_new_place(&local); self.cfg.push_assign(block, source_info, &local, rvalue); } } @@ -1629,10 +1633,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Rvalue::Ref(tcx.types.re_erased, borrow_kind, matched_place.clone()); let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx); let borrowed_input_temp = self.temp(borrowed_input_ty, source_info.span); + let neo_borrowed_input_temp = tcx.as_new_place(&borrowed_input_temp); self.cfg.push_assign( start_block, source_info, - &borrowed_input_temp, + &neo_borrowed_input_temp, borrowed_input ); borrowed_input_temps.push(borrowed_input_temp); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index e0c1f438def36..c769a6ee78196 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -207,7 +207,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { num_enum_variants, values, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); let discr = self.temp(discr_ty, test.span); - self.cfg.push_assign(block, source_info, &discr, + let neo_discr = self.hir.tcx().as_new_place(&discr); + self.cfg.push_assign(block, source_info, &neo_discr, Rvalue::Discriminant(place.clone())); assert_eq!(values.len() + 1, targets.len()); self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt { @@ -284,6 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty)); if opt_ref_ty.is_some() { place = self.temp(ty, test.span); + let place = tcx.as_new_place(&place); self.cfg.push_assign(block, source_info, &place, Rvalue::Cast(CastKind::Unsize, val, ty)); } @@ -295,7 +297,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let slice = self.temp(ty, test.span); - self.cfg.push_assign(block, source_info, &slice, + let neo_slice = tcx.as_new_place(&slice); + self.cfg.push_assign(block, source_info, &neo_slice, Rvalue::Cast(CastKind::Unsize, array, ty)); expect = Operand::Move(slice); } @@ -316,17 +319,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // let lhs_ref_place = &lhs; let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place); let lhs_ref_place = self.temp(ref_ty, test.span); - self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue); + let neo_lhs_ref_place = self.hir.tcx().as_new_place(&lhs_ref_place); + self.cfg.push_assign(block, source_info, &neo_lhs_ref_place, ref_rvalue); let val = Operand::Move(lhs_ref_place); // let rhs_place = rhs; let rhs_place = self.temp(ty, test.span); - self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect)); + let neo_rhs_place = self.hir.tcx().as_new_place(&rhs_place); + self.cfg.push_assign(block, source_info, &neo_rhs_place, Rvalue::Use(expect)); // let rhs_ref_place = &rhs_place; let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place); let rhs_ref_place = self.temp(ref_ty, test.span); - self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue); + let neo_rhs_ref_place = self.hir.tcx().as_new_place(&rhs_ref_place); + self.cfg.push_assign(block, source_info, &neo_rhs_ref_place, ref_rvalue); let expect = Operand::Move(rhs_ref_place); let bool_ty = self.hir.bool_ty(); @@ -389,14 +395,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.temp(bool_ty, test.span)); // actual = len(place) + let neo_actual = self.hir.tcx().as_new_place(&actual); self.cfg.push_assign(block, source_info, - &actual, Rvalue::Len(place.clone())); + &neo_actual, Rvalue::Len(place.clone())); // expected = let expected = self.push_usize(block, source_info, len); // result = actual == expected OR result = actual < expected - self.cfg.push_assign(block, source_info, &result, + let neo_result = self.hir.tcx().as_new_place(&result); + self.cfg.push_assign(block, source_info, &neo_result, Rvalue::BinaryOp(op, Operand::Move(actual), Operand::Move(expected))); @@ -424,7 +432,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // result = op(left, right) let source_info = self.source_info(span); - self.cfg.push_assign(block, source_info, &result, + let neo_result = self.hir.tcx().as_new_place(&result); + self.cfg.push_assign(block, source_info, &neo_result, Rvalue::BinaryOp(op, left, right)); // branch based on result diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 62ec46bb2eed1..dbb9b0b7e52c0 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -57,8 +57,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { -> Place<'tcx> { let usize_ty = self.hir.usize_ty(); let temp = self.temp(usize_ty, source_info.span); + let neo_temp = self.hir.tcx().as_new_place(&temp); self.cfg.push_assign_constant( - block, source_info, &temp, + block, source_info, &neo_temp, Constant { span: source_info.span, ty: self.hir.usize_ty(), diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 9cfcca1edd972..cebdda392ccd5 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -266,7 +266,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { mir::StatementKind::Assign(lhs, rhs) => { // Make sure there are no remaining borrows for variables // that are assigned over. - self.kill_borrows_on_place(sets, lhs); + self.kill_borrows_on_place(sets, &lhs.clone().into_tree()); if let box mir::Rvalue::Ref(_, _, place) = rhs { let neo_place = self.tcx.as_new_place(place); diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index a5e936d4b9e54..e895fa3e41780 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -259,15 +259,16 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match stmt.kind { StatementKind::Assign(ref place, ref rval) => { - self.create_move_path(place); + let place = place.clone().into_tree(); + self.create_move_path(&place); if let RvalueInitializationState::Shallow = rval.initialization_state() { // Box starts out uninitialized - need to create a separate // move-path for the interior so it will be separate from // the exterior. self.create_move_path(&place.clone().deref()); - self.gather_init(place, InitKind::Shallow); + self.gather_init(&place, InitKind::Shallow); } else { - self.gather_init(place, InitKind::Deep); + self.gather_init(&place, InitKind::Deep); } self.gather_rvalue(rval); } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 25f3e4c1f771d..c7600ecfbedf7 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -82,7 +82,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> self.memory.tcx.span = stmt.source_info.span; match stmt.kind { - Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?, + Assign(ref place, ref rvalue) => + self.eval_rvalue_into_place(rvalue, &place.clone().into_tree())?, SetDiscriminant { ref place, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 751815eab287b..988b03293e98a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -422,7 +422,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let rcvr = Place::Local(Local::new(1+0)).deref(); let ret_statement = self.make_statement( StatementKind::Assign( - Place::Local(RETURN_PLACE), + NeoPlace::local(RETURN_PLACE), box Rvalue::Use(Operand::Copy(rcvr)) ) ); @@ -473,9 +473,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ); // `let ref_loc: &ty = &src;` + let neo_ref_loc = tcx.as_new_place(&ref_loc); let statement = self.make_statement( StatementKind::Assign( - ref_loc.clone(), + neo_ref_loc.clone(), box Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, src) ) ); @@ -501,9 +502,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let tcx = self.tcx; let cond = self.make_place(Mutability::Mut, tcx.types.bool); + let neo_cond = tcx.as_new_place(&cond); let compute_cond = self.make_statement( StatementKind::Assign( - cond.clone(), + neo_cond.clone(), box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)) ) ); @@ -538,16 +540,17 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { // `let mut beg = 0;` // `let end = len;` // `goto #1;` + let neo_end = tcx.as_new_place(&end); let inits = vec![ self.make_statement( StatementKind::Assign( - Place::Local(beg), + NeoPlace::local(beg), box Rvalue::Use(Operand::Constant(self.make_usize(0))) ) ), self.make_statement( StatementKind::Assign( - end.clone(), + neo_end.clone(), box Rvalue::Use(Operand::Constant(self.make_usize(len))) ) ) @@ -575,7 +578,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let statements = vec![ self.make_statement( StatementKind::Assign( - Place::Local(beg), + NeoPlace::local(beg), box Rvalue::BinaryOp( BinOp::Add, Operand::Copy(Place::Local(beg)), @@ -598,7 +601,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span)); let init = self.make_statement( StatementKind::Assign( - Place::Local(beg), + NeoPlace::local(beg), box Rvalue::Use(Operand::Constant(self.make_usize(0))) ) ); @@ -625,7 +628,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { // `goto #6;` let statement = self.make_statement( StatementKind::Assign( - Place::Local(beg), + NeoPlace::local(beg), box Rvalue::BinaryOp( BinOp::Add, Operand::Copy(Place::Local(beg)), @@ -743,7 +746,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, statements.push(Statement { source_info, kind: StatementKind::Assign( - Place::Local(ref_rcvr), + NeoPlace::local(ref_rcvr), box Rvalue::Ref(tcx.types.re_erased, borrow_kind, rcvr_l) ) }); @@ -887,7 +890,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, statements: vec![Statement { source_info, kind: StatementKind::Assign( - Place::Local(RETURN_PLACE), + NeoPlace::local(RETURN_PLACE), box Rvalue::Aggregate( box AggregateKind::Adt(adt_def, variant_no, substs, None, None), (1..sig.inputs().len()+1).map(|i| { diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index 2a78dfe473ddd..d00743eb53dd2 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -122,7 +122,7 @@ fn add_move_for_packed_drop<'a, 'tcx>( patch.add_statement( loc, StatementKind::StorageLive(temp)); - patch.add_assign(loc, Place::Local(temp), + patch.add_assign(loc, NeoPlace::local(temp), Rvalue::Use(Operand::Move(location.clone()))); patch.patch_terminator(loc.block, TerminatorKind::Drop { location: Place::Local(temp), diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 8726829fdf77c..b47b3b75ef6e8 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -175,7 +175,8 @@ impl MirPass for AddRetag { // Assignments of reference or ptr type are the ones where we may have // to update tags. This includes `x = &[mut] ...` and hence // we also retag after taking a reference! - StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => { + StatementKind::Assign(ref place, box ref rvalue) if + needs_retag(&place.clone().into_tree()) => { let kind = match rvalue { Rvalue::Ref(_, borrow_kind, _) if borrow_kind.allows_two_phase_borrow() @@ -193,7 +194,7 @@ impl MirPass for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert(i+1, Statement { source_info, - kind: StatementKind::Retag(retag_kind, place.clone()), + kind: StatementKind::Retag(retag_kind, place.clone().into_tree()), }); } } diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index e6df6b7fd2724..d6e33bf6d070e 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -22,7 +22,7 @@ use rustc_data_structures::fx::FxHashSet; -use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place}; +use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place, NeoPlace, PlaceBase}; use rustc::mir::{Statement, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; @@ -103,7 +103,10 @@ impl<'tcx> MutVisitor<'tcx> for DeleteFakeBorrows { block: BasicBlock, statement: &mut Statement<'tcx>, location: Location) { - if let StatementKind::Assign(Place::Local(local), _) = statement.kind { + if let StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, _) = statement.kind { if self.fake_borrow_temporaries.contains(&local) { statement.make_nop(); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index b63d1f4cc335c..08ec3a8704246 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -553,13 +553,12 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { ) { trace!("visit_statement: {:?}", statement); if let StatementKind::Assign(ref place, ref rval) = statement.kind { - let neo_place = self.tcx.as_new_place(place); - let place_ty: ty::Ty<'tcx> = neo_place + let place_ty: ty::Ty<'tcx> = place .ty(&self.mir.local_decls, self.tcx) .to_ty(self.tcx); if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { - if let Place::Local(local) = *place { + if let Some(local) = place.as_local() { trace!("checking whether {:?} can be stored to {:?}", value, local); if self.can_const_prop[local] { trace!("storing {:?} to {:?}", value, local); diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 55e14077c3ed0..8a6e1b8e89f75 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -19,7 +19,10 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use rustc::mir::{Constant, Local, LocalKind, Location, Place, Mir, Operand, Rvalue, StatementKind}; +use rustc::mir::{ + Constant, Local, LocalKind, Location, Place, NeoPlace, PlaceBase, + Mir, Operand, Rvalue, StatementKind +}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use transform::{MirPass, MirSource}; @@ -94,7 +97,10 @@ impl MirPass for CopyPropagation { // That use of the source must be an assignment. match statement.kind { - StatementKind::Assign(Place::Local(local), box Rvalue::Use(ref operand)) if + StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, box Rvalue::Use(ref operand)) if local == dest_local => { let maybe_action = match *operand { Operand::Copy(ref src_place) | @@ -144,11 +150,17 @@ fn eliminate_self_assignments<'tcx>( if let Some(stmt) = mir[location.block].statements.get(location.statement_index) { match stmt.kind { StatementKind::Assign( - Place::Local(local), + NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, box Rvalue::Use(Operand::Copy(Place::Local(src_local))), ) | StatementKind::Assign( - Place::Local(local), + NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, box Rvalue::Use(Operand::Move(Place::Local(src_local))), ) if local == dest_local && dest_local == src_local => {} _ => { diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index a2fe9def8eeba..e3c5e4ad87852 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -33,7 +33,7 @@ impl MirPass for Deaggregator { let (mut lhs, kind, operands) = match stmt.kind { StatementKind::Assign(lhs, box rvalue) => { match rvalue { - Rvalue::Aggregate(kind, operands) => (lhs, kind, operands), + Rvalue::Aggregate(kind, operands) => (lhs.into_tree(), kind, operands), _ => bug!() } } @@ -74,6 +74,7 @@ impl MirPass for Deaggregator { let field = Field::new(active_field_index.unwrap_or(i)); lhs.clone().field(field, ty) }; + let lhs_field = tcx.as_new_place(&lhs_field); Statement { source_info, kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)), diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 06e16de8b43bc..78b769b59f088 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -469,7 +469,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); let assign = Statement { - kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())), + kind: StatementKind::Assign(self.tcx.as_new_place(&location.clone()), + box Rvalue::Use(value.clone())), source_info: terminator.source_info }; @@ -543,7 +544,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { if let Some(&flag) = self.drop_flags.get(&path) { let span = self.patch.source_info_for_location(self.mir, loc).span; let val = self.constant_bool(span, val.value()); - self.patch.add_assign(loc, Place::Local(flag), val); + self.patch.add_assign(loc, + self.tcx.as_new_place(&Place::Local(flag)), + val); } } @@ -552,7 +555,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { - self.patch.add_assign(loc, Place::Local(*flag), false_.clone()); + self.patch.add_assign(loc, + self.tcx.as_new_place(&Place::Local(*flag)), + false_.clone()); } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index ec0c118634d0f..06f4efa9faa38 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -177,6 +177,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { ty::ParamEnv::empty().and(self.tcx.types.u32) ))), }); + let state = self.tcx.as_new_place(&state); Statement { source_info, kind: StatementKind::Assign(state, box Rvalue::Use(val)), @@ -234,9 +235,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { if let Some((state_idx, resume, v, drop)) = ret_val { let source_info = data.terminator().source_info; // We must assign the value first in case it gets declared dead below + let place = NeoPlace::local(RETURN_PLACE); data.statements.push(Statement { source_info, - kind: StatementKind::Assign(Place::Local(RETURN_PLACE), + kind: StatementKind::Assign(place, box self.make_state(state_idx, v)), }); let state = if let Some(resume) = resume { // Yield diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index b5b950fba0297..cd16ebca7e5cc 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -455,15 +455,14 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let temp = LocalDecl::new_temp(ty, callsite.location.span); let tmp = caller_mir.local_decls.push(temp); - let tmp = Place::Local(tmp); - + let tmp = NeoPlace::local(tmp); let stmt = Statement { source_info: callsite.location, kind: StatementKind::Assign(tmp.clone(), box dest) }; caller_mir[callsite.bb] .statements.push(stmt); - tmp.deref() + tmp.into_tree().deref() } else { destination.0 }; @@ -605,9 +604,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); let arg_tmp = caller_mir.local_decls.push(arg_tmp); + let place = NeoPlace::local(arg_tmp); let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(Place::Local(arg_tmp), box arg), + kind: StatementKind::Assign(place, box arg), }; caller_mir[callsite.bb].statements.push(stmt); arg_tmp diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index a1a26fecb9d0a..d32fcfb218e37 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -87,7 +87,7 @@ impl Lower128Bit { block.statements.push(Statement { source_info: source_info, kind: StatementKind::Assign( - Place::Local(local), + NeoPlace::local(local), box Rvalue::Cast( CastKind::Misc, rhs, @@ -97,7 +97,7 @@ impl Lower128Bit { } let call_did = check_lang_item_type( - lang_item, &place, &lhs, &rhs, local_decls, tcx); + lang_item, &place.clone().into_tree(), &lhs, &rhs, local_decls, tcx); let bb = BasicBlock::new(cur_len + new_blocks.len()); new_blocks.push(after_call); @@ -109,7 +109,7 @@ impl Lower128Bit { func: Operand::function_handle(tcx, call_did, List::empty(), source_info.span), args: vec![lhs, rhs], - destination: Some((place, bb)), + destination: Some((place.into_tree(), bb)), cleanup: None, from_hir_call: false, }, diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index f2bc9025670c9..98976ad1ca5dd 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -172,12 +172,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { let last = self.promoted.basic_blocks().last().unwrap(); let data = &mut self.promoted[last]; + let place = NeoPlace::local(dest); data.statements.push(Statement { source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }, - kind: StatementKind::Assign(Place::Local(dest), box rvalue) + kind: StatementKind::Assign(place, box rvalue) }); } @@ -373,7 +374,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, match candidate { Candidate::Ref(Location { block, statement_index }) => { match mir[block].statements[statement_index].kind { - StatementKind::Assign(Place::Local(local), _) => { + StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(local), + elems: &[], + }, _) => { if temps[local] == TempState::PromotedOut { // Already promoted. continue; @@ -420,7 +424,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, for block in mir.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { - StatementKind::Assign(Place::Local(index), _) | + StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(index), + elems: &[], + }, _) | StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { !promoted(index) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2e55dce4ea93c..b9e42e1c09eb9 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -187,6 +187,70 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { self.add(original); } + /// Assign the current qualification to the given destination. + fn neo_assign(&mut self, dest: &NeoPlace<'tcx>, location: Location) { + trace!("assign: {:?}", dest); + let qualif = self.qualif; + let span = self.span; + let store = |slot: &mut Option| { + if slot.is_some() { + span_bug!(span, "multiple assignments to {:?}", dest); + } + *slot = Some(qualif); + }; + + // Only handle promotable temps in non-const functions. + if self.mode == Mode::Fn { + if let Some(index) = dest.as_local() { + if self.mir.local_kind(index) == LocalKind::Temp + && self.temp_promotion_state[index].is_promotable() { + debug!("store to promotable temp {:?} ({:?})", index, qualif); + store(&mut self.local_qualif[index]); + } + } + return; + } + + // projections are transparent for assignments + // we qualify the entire destination at once, even if just a field would have + // stricter qualification + if !dest.elems.is_empty() { + // Catch more errors in the destination. `visit_place` also checks various + // projection rules like union field access and raw pointer deref + self.visit_neoplace( + dest, + PlaceContext::MutatingUse(MutatingUseContext::Store), + location + ); + } + + let index = match dest.base { + // We treat all locals equal in constants + PlaceBase::Local(index) => index, + PlaceBase::Promoted(..) => bug!("promoteds don't exist yet during promotion"), + PlaceBase::Static(..) => { + // Catch more errors in the destination. `visit_place` also checks that we + // do not try to access statics from constants or try to mutate statics + self.visit_neoplace( + dest, + PlaceContext::MutatingUse(MutatingUseContext::Store), + location + ); + return; + } + }; + debug!("store to var {:?}", index); + match &mut self.local_qualif[index] { + // this is overly restrictive, because even full assignments do not clear the qualif + // While we could special case full assignments, this would be inconsistent with + // aggregates where we overwrite all fields via assignments, which would not get + // that feature. + Some(ref mut qualif) => *qualif = *qualif | self.qualif, + // insert new qualification + qualif @ None => *qualif = Some(self.qualif), + } + } + /// Assign the current qualification to the given destination. fn assign(&mut self, dest: &Place<'tcx>, location: Location) { trace!("assign: {:?}", dest); @@ -1069,13 +1133,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { fn visit_assign(&mut self, _: BasicBlock, - dest: &Place<'tcx>, + dest: &NeoPlace<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location); self.visit_rvalue(rvalue, location); - self.assign(dest, location); + self.neo_assign(dest, location); } fn visit_source_info(&mut self, source_info: &SourceInfo) { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 85bf1e70ebf42..31ebd9e15fd25 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -209,7 +209,7 @@ fn check_statement( let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(place, rval) => { - check_place(tcx, mir, place, span)?; + check_place(tcx, mir, &place.clone().into_tree(), span)?; check_rvalue(tcx, mir, rval, span) } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index c8ef2decf2606..e57aba77e0e20 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -47,7 +47,10 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(Place::Local(_), box Rvalue::Use(_)) => { + StatementKind::Assign(NeoPlace { + base: PlaceBase::Local(_), + elems: &[], + }, box Rvalue::Use(_)) => { // Writing to a local (e.g., a drop flag) does not // turn a landing pad to a non-nop } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 36a6279e50320..2d88a58aed3ab 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -159,7 +159,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "sanity_check should run before Deaggregator inserts SetDiscriminant"), }; - if place == peek_arg_place { + if &place.clone().into_tree() == peek_arg_place { if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue { // Okay, our search is over. match move_data.rev_lookup.find(peeking_at_place) { @@ -186,7 +186,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let lhs_mpi = move_data.rev_lookup.find(place); + let lhs_mpi = move_data.rev_lookup.find(&place.clone().into_tree()); debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}", place, lhs_mpi, stmt); diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 20eeb6eb236f9..e641710602aa0 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -59,7 +59,7 @@ struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { fn visit_assign(&mut self, block: BasicBlock, - dst_place: &Place<'tcx>, + dst_place: &NeoPlace<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { @@ -76,7 +76,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { assert!(size <= u32::max_value() as u64, "uniform array move out doesn't supported for array bigger then u32"); - self.uniform(location, dst_place, proj, item_ty, size as u32); + self.uniform(location, &dst_place.clone().into_tree(), proj, item_ty, size as u32); } } @@ -102,7 +102,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { let temp = self.patch.new_temp(item_ty, self.mir.source_info(location).span); self.patch.add_statement(location, StatementKind::StorageLive(temp)); self.patch.add_assign(location, - Place::Local(temp), + NeoPlace::local(temp), Rvalue::Use( Operand::Move( Place::Projection(box PlaceProjection{ @@ -114,8 +114,9 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { })))); temp }).collect(); + let neo_dst_place = self.tcx.as_new_place(&dst_place); self.patch.add_assign(location, - dst_place.clone(), + neo_dst_place.clone(), Rvalue::Aggregate(box AggregateKind::Array(item_ty), temps.iter().map( |x| Operand::Move(Place::Local(*x))).collect() @@ -127,8 +128,9 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { // uniforms statements like _11 = move _2[-1 of 1]; ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { self.patch.make_nop(location); + let neo_dst_place = self.tcx.as_new_place(&dst_place); self.patch.add_assign(location, - dst_place.clone(), + neo_dst_place.clone(), Rvalue::Use( Operand::Move( Place::Projection(box PlaceProjection{ @@ -217,7 +219,7 @@ impl RestoreSubsliceArrayMoveOut { items: &[Option<(&LocalUse, u32, &Place<'tcx>)>], opt_size: Option, patch: &mut MirPatch<'tcx>, - dst_place: &Place<'tcx>) { + dst_place: &NeoPlace<'tcx>) { let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); if opt_size.is_some() && items.iter().all( @@ -259,7 +261,10 @@ impl RestoreSubsliceArrayMoveOut { if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( - Place::Local(_), + NeoPlace { + base: PlaceBase::Local(_), + elems: &[], + }, box Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{ ref base, elem: ProjectionElem::ConstantIndex{ offset, min_length: _, from_end: false}})))) = statement.kind { @@ -293,7 +298,7 @@ struct RestoreDataCollector { impl<'tcx> Visitor<'tcx> for RestoreDataCollector { fn visit_assign(&mut self, block: BasicBlock, - place: &Place<'tcx>, + place: &NeoPlace<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 355467f9e73be..a97c0d172b01b 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -487,14 +487,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // discriminant after it is free-ed, because that // way lies only trouble. let discr_ty = adt.repr.discr_type().to_ty(self.tcx()); - let discr = Place::Local(self.new_temp(discr_ty)); + let discr = NeoPlace::local(self.new_temp(discr_ty)); let discr_rv = Rvalue::Discriminant(self.place.clone()); let switch_block = BasicBlockData { statements: vec![self.assign(&discr, discr_rv)], terminator: Some(Terminator { source_info: self.source_info, kind: TerminatorKind::SwitchInt { - discr: Operand::Move(discr), + discr: Operand::Move(discr.into_tree()), switch_ty: discr_ty, values: From::from(values.to_owned()), targets: blocks, @@ -525,7 +525,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let result = BasicBlockData { statements: vec![self.assign( - &Place::Local(ref_place), + &NeoPlace::local(ref_place), Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, self.place.clone()) @@ -601,10 +601,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> Rvalue::BinaryOp(BinOp::Add, copy(&Place::Local(cur)), one)) }; + let neo_ptr = tcx.as_new_place(&ptr); + let place = NeoPlace::local(cur); let drop_block = BasicBlockData { statements: vec![ - self.assign(ptr, ptr_next), - self.assign(&Place::Local(cur), cur_next) + self.assign(&neo_ptr, ptr_next), + self.assign(&place, cur_next) ], is_cleanup: unwind.is_cleanup(), terminator: Some(Terminator { @@ -615,9 +617,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }; let drop_block = self.elaborator.patch().new_block(drop_block); + let neo_can_go = tcx.as_new_place(can_go); let loop_block = BasicBlockData { statements: vec![ - self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq, + self.assign(&neo_can_go, Rvalue::BinaryOp(BinOp::Eq, copy(&Place::Local(cur)), copy(length_or_end))) ], @@ -668,13 +671,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); let tcx = self.tcx(); - let size = &Place::Local(self.new_temp(tcx.types.usize)); - let size_is_zero = &Place::Local(self.new_temp(tcx.types.bool)); + let size = &NeoPlace::local(self.new_temp(tcx.types.usize)); + let size_is_zero = &NeoPlace::local(self.new_temp(tcx.types.bool)); let base_block = BasicBlockData { statements: vec![ self.assign(size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), self.assign(size_is_zero, Rvalue::BinaryOp(BinOp::Eq, - move_(size), + move_(&size.clone().into_tree()), self.constant_usize(0))) ], is_cleanup: self.unwind.is_cleanup(), @@ -682,7 +685,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> source_info: self.source_info, kind: TerminatorKind::if_( tcx, - move_(size_is_zero), + move_(&size_is_zero.clone().into_tree()), self.drop_loop_pair(ety, false), self.drop_loop_pair(ety, true) ) @@ -732,28 +735,33 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let cur = Place::Local(cur); let zero = self.constant_usize(0); let mut drop_block_stmts = vec![]; - drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.place.clone()))); + let neo_length = tcx.as_new_place(&length); + drop_block_stmts.push(self.assign(&neo_length, Rvalue::Len(self.place.clone()))); if ptr_based { let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); let tmp = Place::Local(self.new_temp(tmp_ty)); // tmp = &mut P; // cur = tmp as *mut T; // end = Offset(cur, len); - drop_block_stmts.push(self.assign(&tmp, Rvalue::Ref( + let neo_tmp = tcx.as_new_place(&tmp); + drop_block_stmts.push(self.assign(&neo_tmp, Rvalue::Ref( tcx.types.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, self.place.clone() ))); - drop_block_stmts.push(self.assign(&cur, Rvalue::Cast( + let neo_cur = tcx.as_new_place(&cur); + drop_block_stmts.push(self.assign(&neo_cur, Rvalue::Cast( CastKind::Misc, Operand::Move(tmp), iter_ty ))); - drop_block_stmts.push(self.assign(&length_or_end, + let neo_length_or_end = tcx.as_new_place(&length_or_end); + drop_block_stmts.push(self.assign(&neo_length_or_end, Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length) ))); } else { // index = 0 (length already pushed) - drop_block_stmts.push(self.assign(&cur, Rvalue::Use(zero))); + let neo_cur = tcx.as_new_place(&cur); + drop_block_stmts.push(self.assign(&neo_cur, Rvalue::Use(zero))); } let drop_block = self.elaborator.patch().new_block(BasicBlockData { statements: drop_block_stmts, @@ -970,7 +978,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }) } - fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { + fn assign(&self, lhs: &NeoPlace<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { Statement { source_info: self.source_info, kind: StatementKind::Assign(lhs.clone(), box rhs) diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 5a1f94677a1d4..6864dce180d25 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -119,7 +119,7 @@ impl<'tcx> MirPatch<'tcx> { self.new_statements.push((loc, stmt)); } - pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { + pub fn add_assign(&mut self, loc: Location, place: NeoPlace<'tcx>, rv: Rvalue<'tcx>) { self.add_statement(loc, StatementKind::Assign(place, box rv)); }