diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 783964c701ad5..d8b641fbe31f4 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1718,11 +1718,11 @@ impl<'tcx> Debug for Statement<'tcx> { #[derive( Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, )] -pub enum Place<'tcx> { - Base(PlaceBase<'tcx>), +pub struct Place<'tcx> { + pub base: PlaceBase<'tcx>, /// projection out of a place (access a field, deref a pointer, etc) - Projection(Box>), + pub projection: Option>>, } #[derive( @@ -1761,7 +1761,7 @@ impl_stable_hash_for!(struct Static<'tcx> { Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, )] pub struct Projection<'tcx> { - pub base: Place<'tcx>, + pub base: Option>>, pub elem: PlaceElem<'tcx>, } @@ -1826,8 +1826,17 @@ newtype_index! { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct PlaceRef<'a, 'tcx> { + pub base: &'a PlaceBase<'tcx>, + pub projection: &'a Option>>, +} + impl<'tcx> Place<'tcx> { - pub const RETURN_PLACE: Place<'tcx> = Place::Base(PlaceBase::Local(RETURN_PLACE)); + pub const RETURN_PLACE: Place<'tcx> = Place { + base: PlaceBase::Local(RETURN_PLACE), + projection: None, + }; pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { self.elem(ProjectionElem::Field(f, ty)) @@ -1853,7 +1862,10 @@ impl<'tcx> Place<'tcx> { } pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { - Place::Projection(Box::new(Projection { base: self, elem })) + Place { + base: self.base, + projection: Some(Box::new(Projection { base: self.projection, elem })), + } } /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or @@ -1862,54 +1874,77 @@ impl<'tcx> Place<'tcx> { // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? pub fn local_or_deref_local(&self) -> Option { match self { - Place::Base(PlaceBase::Local(local)) - | Place::Projection(box Projection { - base: Place::Base(PlaceBase::Local(local)), - elem: ProjectionElem::Deref, - }) => Some(*local), + Place { + base: PlaceBase::Local(local), + projection: None, + } | + Place { + base: PlaceBase::Local(local), + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }), + } => Some(*local), _ => None, } } - /// Finds the innermost `Local` from this `Place`. - pub fn base_local(&self) -> Option { - let mut place = self; - loop { - match place { - Place::Projection(proj) => place = &proj.base, - Place::Base(PlaceBase::Static(_)) => return None, - Place::Base(PlaceBase::Local(local)) => return Some(*local), - } - } - } - /// Recursively "iterates" over place components, generating a `PlaceBase` and /// `Projections` list and invoking `op` with a `ProjectionsIter`. pub fn iterate( &self, op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, ) -> R { - self.iterate2(&Projections::Empty, op) + Place::iterate_over(&self.base, &self.projection, op) } - fn iterate2( - &self, - next: &Projections<'_, 'tcx>, + pub fn iterate_over( + place_base: &PlaceBase<'tcx>, + place_projection: &Option>>, op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, ) -> R { - match self { - Place::Projection(interior) => { - interior.base.iterate2(&Projections::List { projection: interior, next }, op) + fn iterate_over2<'tcx, R>( + place_base: &PlaceBase<'tcx>, + place_projection: &Option>>, + next: &Projections<'_, 'tcx>, + op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, + ) -> R { + match place_projection { + None => { + op(place_base, next.iter()) + } + + Some(interior) => { + iterate_over2( + place_base, + &interior.base, + &Projections::List { + projection: interior, + next, + }, + op, + ) + } } + } - Place::Base(base) => op(base, next.iter()), + iterate_over2(place_base, place_projection, &Projections::Empty, op) + } + + pub fn as_place_ref(&self) -> PlaceRef<'_, 'tcx> { + PlaceRef { + base: &self.base, + projection: &self.projection, } } } impl From for Place<'_> { fn from(local: Local) -> Self { - Place::Base(local.into()) + Place { + base: local.into(), + projection: None, + } } } @@ -1919,6 +1954,36 @@ impl From for PlaceBase<'_> { } } +impl<'a, 'tcx> PlaceRef<'a, 'tcx> { + pub fn iterate( + &self, + op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, + ) -> R { + Place::iterate_over(self.base, self.projection, op) + } + + /// Finds 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_or_deref_local(&self) -> Option { + match self { + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } | + PlaceRef { + base: PlaceBase::Local(local), + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }), + } => Some(*local), + _ => None, + } + } +} + /// A linked list of projections running up the stack; begins with the /// innermost projection and extends to the outermost (e.g., `a.b.c` /// would have the place `b` with a "next" pointer to `b.c`). @@ -3155,18 +3220,14 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - match self { - &Place::Projection(ref p) => Place::Projection(p.fold_with(folder)), - _ => self.clone(), + Place { + base: self.base.clone(), + projection: self.projection.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - if let &Place::Projection(ref p) = self { - p.visit_with(visitor) - } else { - false - } + self.projection.visit_with(visitor) } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 2079a2a34e7ef..e2f5d192281a7 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -118,11 +118,15 @@ BraceStructTypeFoldableImpl! { } impl<'tcx> Place<'tcx> { - pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> - where - D: HasLocalDecls<'tcx>, + pub fn ty_from( + base: &PlaceBase<'tcx>, + projection: &Option>>, + local_decls: &D, + tcx: TyCtxt<'tcx> + ) -> PlaceTy<'tcx> + where D: HasLocalDecls<'tcx> { - self.iterate(|place_base, place_projections| { + Place::iterate_over(base, projection, |place_base, place_projections| { let mut place_ty = place_base.ty(local_decls); for proj in place_projections { @@ -132,6 +136,13 @@ impl<'tcx> Place<'tcx> { place_ty }) } + + pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> + where + D: HasLocalDecls<'tcx>, + { + Place::ty_from(&self.base, &self.projection, local_decls, tcx) + } } impl<'tcx> PlaceBase<'tcx> { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index babce812d4a39..c3a4566b5aee3 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -159,10 +159,11 @@ macro_rules! make_mir_visitor { } fn visit_projection(&mut self, + place_base: & $($mutability)? PlaceBase<'tcx>, place: & $($mutability)? Projection<'tcx>, context: PlaceContext, location: Location) { - self.super_projection(place, context, location); + self.super_projection(place_base, place, context, location); } fn visit_constant(&mut self, @@ -676,19 +677,20 @@ macro_rules! make_mir_visitor { place: & $($mutability)? Place<'tcx>, context: PlaceContext, location: Location) { - match place { - Place::Base(place_base) => { - self.visit_place_base(place_base, context, location); - } - Place::Projection(proj) => { - let context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; + let mut context = context; + + if place.projection.is_some() { + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + } - self.visit_projection(proj, context, location); - } + self.visit_place_base(& $($mutability)? place.base, context, location); + + if let Some(box proj) = & $($mutability)? place.projection { + self.visit_projection(& $($mutability)? place.base, proj, context, location); } } @@ -707,13 +709,14 @@ macro_rules! make_mir_visitor { } fn super_projection(&mut self, + place_base: & $($mutability)? PlaceBase<'tcx>, proj: & $($mutability)? Projection<'tcx>, context: PlaceContext, location: Location) { - // this is calling `super_place` in preparation for changing `Place` to be - // a struct with a base and a slice of projections. `visit_place` should only ever - // be called for the outermost place now. - self.super_place(& $($mutability)? proj.base, context, location); + if let Some(box proj_base) = & $($mutability)? proj.base { + self.visit_projection(place_base, proj_base, context, location); + } + match & $($mutability)? proj.elem { ProjectionElem::Deref => { } diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 2af9b448ef1eb..09c346117f9d9 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -92,6 +92,86 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { self.first_assignment[local] = location; } } + + fn process_place(&mut self, + place_ref: &mir::PlaceRef<'_, 'tcx>, + context: PlaceContext, + location: Location) { + let cx = self.fx.cx; + + if let Some(proj) = place_ref.projection { + // Allow uses of projections that are ZSTs or from scalar fields. + let is_consume = match context { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true, + _ => false + }; + if is_consume { + let base_ty = + mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx()); + let base_ty = self.fx.monomorphize(&base_ty); + + // ZSTs don't require any actual memory access. + let elem_ty = base_ty + .projection_ty(cx.tcx(), &proj.elem) + .ty; + let elem_ty = self.fx.monomorphize(&elem_ty); + if cx.layout_of(elem_ty).is_zst() { + return; + } + + if let mir::ProjectionElem::Field(..) = proj.elem { + let layout = cx.layout_of(base_ty.ty); + if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { + // Recurse with the same context, instead of `Projection`, + // potentially stopping at non-operand projections, + // which would trigger `not_ssa` on locals. + self.process_place( + &mir::PlaceRef { + base: place_ref.base, + projection: &proj.base, + }, + context, + location, + ); + return; + } + } + } + + // A deref projection only reads the pointer, never needs the place. + if let mir::ProjectionElem::Deref = proj.elem { + self.process_place( + &mir::PlaceRef { + base: place_ref.base, + projection: &proj.base, + }, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location + ); + return; + } + } + + // FIXME this is super_place code, is repeated here to avoid cloning place or changing + // visit_place API + let mut context = context; + + if place_ref.projection.is_some() { + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + } + + self.visit_place_base(place_ref.base, context, location); + + if let Some(box proj) = place_ref.projection { + self.visit_projection(place_ref.base, proj, context, location); + } + } + } impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> @@ -103,7 +183,10 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> location: Location) { debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); - if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place { + if let mir::Place { + base: mir::PlaceBase::Local(index), + projection: None, + } = *place { self.assign(index, location); if !self.fx.rvalue_creates_operand(rvalue) { self.not_ssa(index); @@ -155,51 +238,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> context: PlaceContext, location: Location) { debug!("visit_place(place={:?}, context={:?})", place, context); - let cx = self.fx.cx; - - if let mir::Place::Projection(ref proj) = *place { - // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true, - _ => false - }; - if is_consume { - let base_ty = proj.base.ty(self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(&base_ty); - - // ZSTs don't require any actual memory access. - let elem_ty = base_ty - .projection_ty(cx.tcx(), &proj.elem) - .ty; - let elem_ty = self.fx.monomorphize(&elem_ty); - if cx.layout_of(elem_ty).is_zst() { - return; - } - - if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.ty); - if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { - // Recurse with the same context, instead of `Projection`, - // potentially stopping at non-operand projections, - // which would trigger `not_ssa` on locals. - self.visit_place(&proj.base, context, location); - return; - } - } - } - - // A deref projection only reads the pointer, never needs the place. - if let mir::ProjectionElem::Deref = proj.elem { - return self.visit_place( - &proj.base, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); - } - } - - self.super_place(place, context, location); + self.process_place(&place.as_place_ref(), context, location); } fn visit_local(&mut self, diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 941166ccfab09..d4b434ffe809c 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -253,7 +253,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { PassMode::Direct(_) | PassMode::Pair(..) => { let op = - self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE); + self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_place_ref()); if let Ref(llval, _, align) = op.val { bx.load(llval, align) } else { @@ -314,7 +314,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return } - let place = self.codegen_place(&mut bx, location); + let place = self.codegen_place(&mut bx, &location.as_place_ref()); let (args1, args2); let mut args = if let Some(llextra) = place.llextra { args2 = [place.llval, llextra]; @@ -607,18 +607,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // but specified directly in the code. This means it gets promoted // and we can then extract the value by evaluating the promoted. mir::Operand::Copy( - Place::Base( - PlaceBase::Static( - box Static { kind: StaticKind::Promoted(promoted), ty } - ) - ) + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted), + ty, + }), + projection: None, + } ) | mir::Operand::Move( - Place::Base( - PlaceBase::Static( - box Static { kind: StaticKind::Promoted(promoted), ty } - ) - ) + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted), + ty, + }), + projection: None, + } ) => { let param_env = ty::ParamEnv::reveal_all(); let cid = mir::interpret::GlobalId { @@ -1098,7 +1102,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if fn_ret.is_ignore() { return ReturnDest::Nothing; } - let dest = if let mir::Place::Base(mir::PlaceBase::Local(index)) = *dest { + let dest = if let mir::Place { + base: mir::PlaceBase::Local(index), + projection: None, + } = *dest { match self.locals[index] { LocalRef::Place(dest) => dest, LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), @@ -1128,7 +1135,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } else { - self.codegen_place(bx, dest) + self.codegen_place(bx, &mir::PlaceRef { + base: &dest.base, + projection: &dest.projection, + }) }; if fn_ret.is_indirect() { if dest.align < dest.layout.align.abi { @@ -1153,12 +1163,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { src: &mir::Operand<'tcx>, dst: &mir::Place<'tcx> ) { - if let mir::Place::Base(mir::PlaceBase::Local(index)) = *dst { + if let mir::Place { + base: mir::PlaceBase::Local(index), + projection: None, + } = *dst { match self.locals[index] { LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), LocalRef::Operand(None) => { - let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst)); + let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_place_ref())); assert!(!dst_layout.ty.has_erasable_regions()); let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp"); place.storage_live(bx); @@ -1173,7 +1186,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } else { - let dst = self.codegen_place(bx, dst); + let dst = self.codegen_place(bx, &dst.as_place_ref()); self.codegen_transmute_into(bx, src, dst); } } diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 4a6752fec3556..0f6a95c1968b8 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -380,11 +380,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn maybe_codegen_consume_direct( &mut self, bx: &mut Bx, - place: &mir::Place<'tcx> + place_ref: &mir::PlaceRef<'_, 'tcx> ) -> Option> { - debug!("maybe_codegen_consume_direct(place={:?})", place); + debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); - place.iterate(|place_base, place_projection| { + place_ref.iterate(|place_base, place_projection| { if let mir::PlaceBase::Local(index) = place_base { match self.locals[*index] { LocalRef::Operand(Some(mut o)) => { @@ -413,7 +413,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(o) } LocalRef::Operand(None) => { - bug!("use of {:?} before def", place); + bug!("use of {:?} before def", place_ref); } LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { // watch out for locals that do not have an @@ -430,11 +430,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_consume( &mut self, bx: &mut Bx, - place: &mir::Place<'tcx> + place_ref: &mir::PlaceRef<'_, 'tcx> ) -> OperandRef<'tcx, Bx::Value> { - debug!("codegen_consume(place={:?})", place); + debug!("codegen_consume(place_ref={:?})", place_ref); - let ty = self.monomorphized_place_ty(place); + let ty = self.monomorphized_place_ty(place_ref); let layout = bx.cx().layout_of(ty); // ZSTs don't require any actual memory access. @@ -442,13 +442,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return OperandRef::new_zst(bx, layout); } - if let Some(o) = self.maybe_codegen_consume_direct(bx, place) { + if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) { return o; } // for most places, to consume them we just load them // out from their home - let place = self.codegen_place(bx, place); + let place = self.codegen_place(bx, place_ref); bx.load_operand(place) } @@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match *operand { mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => { - self.codegen_consume(bx, place) + self.codegen_consume(bx, &place.as_place_ref()) } mir::Operand::Constant(ref constant) => { diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 588badfa11af2..b38e58baaf6a4 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -428,16 +428,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_place( &mut self, bx: &mut Bx, - place: &mir::Place<'tcx> + place_ref: &mir::PlaceRef<'_, 'tcx> ) -> PlaceRef<'tcx, Bx::Value> { - debug!("codegen_place(place={:?})", place); - + debug!("codegen_place(place_ref={:?})", place_ref); let cx = self.cx; let tcx = self.cx.tcx(); - let result = match *place { - mir::Place::Base(mir::PlaceBase::Local(index)) => { - match self.locals[index] { + let result = match &place_ref { + mir::PlaceRef { + base: mir::PlaceBase::Local(index), + projection: None, + } => { + match self.locals[*index] { LocalRef::Place(place) => { return place; } @@ -445,19 +447,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return bx.load_operand(place).deref(cx); } LocalRef::Operand(..) => { - bug!("using operand local {:?} as place", place); + bug!("using operand local {:?} as place", place_ref); } } } - mir::Place::Base( - mir::PlaceBase::Static( - box mir::Static { ty, kind: mir::StaticKind::Promoted(promoted) } - ) - ) => { + mir::PlaceRef { + base: mir::PlaceBase::Static(box mir::Static { + ty, + kind: mir::StaticKind::Promoted(promoted), + }), + projection: None, + } => { let param_env = ty::ParamEnv::reveal_all(); let cid = mir::interpret::GlobalId { instance: self.instance, - promoted: Some(promoted), + promoted: Some(*promoted), }; let layout = cx.layout_of(self.monomorphize(&ty)); match bx.tcx().const_eval(param_env.and(cid)) { @@ -480,26 +484,41 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - mir::Place::Base( - mir::PlaceBase::Static( - box mir::Static { ty, kind: mir::StaticKind::Static(def_id) } - ) - ) => { + mir::PlaceRef { + base: mir::PlaceBase::Static(box mir::Static { + ty, + kind: mir::StaticKind::Static(def_id), + }), + projection: None, + } => { // NB: The layout of a static may be unsized as is the case when working // with a static that is an extern_type. let layout = cx.layout_of(self.monomorphize(&ty)); - let static_ = bx.get_static(def_id); + let static_ = bx.get_static(*def_id); PlaceRef::new_thin_place(bx, static_, layout, layout.align.abi) }, - mir::Place::Projection(box mir::Projection { - ref base, - elem: mir::ProjectionElem::Deref - }) => { + mir::PlaceRef { + base, + projection: Some(box mir::Projection { + base: proj_base, + elem: mir::ProjectionElem::Deref, + }), + } => { // Load the pointer from its location. - self.codegen_consume(bx, base).deref(bx.cx()) + self.codegen_consume(bx, &mir::PlaceRef { + base, + projection: proj_base, + }).deref(bx.cx()) } - mir::Place::Projection(ref projection) => { - let cg_base = self.codegen_place(bx, &projection.base); + mir::PlaceRef { + base, + projection: Some(projection), + } => { + // FIXME turn this recursion into iteration + let cg_base = self.codegen_place(bx, &mir::PlaceRef { + base, + projection: &projection.base, + }); match projection.elem { mir::ProjectionElem::Deref => bug!(), @@ -553,13 +572,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } }; - debug!("codegen_place(place={:?}) => {:?}", place, result); + debug!("codegen_place(place={:?}) => {:?}", place_ref, result); result } - pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { + pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); - let place_ty = place.ty(self.mir, tcx); + let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, self.mir, tcx); self.monomorphize(&place_ty.ty) } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 4a1971e3e2ee0..cfb7db7365802 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -355,7 +355,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Rvalue::Ref(_, bk, ref place) => { - let cg_place = self.codegen_place(&mut bx, place); + let cg_place = self.codegen_place(&mut bx, &place.as_place_ref()); let ty = cg_place.layout.ty; @@ -446,7 +446,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Discriminant(ref place) => { let discr_ty = rvalue.ty(&*self.mir, bx.tcx()); - let discr = self.codegen_place(&mut bx, place) + let discr = self.codegen_place(&mut bx, &place.as_place_ref()) .codegen_get_discr(&mut bx, discr_ty); (bx, OperandRef { val: OperandValue::Immediate(discr), @@ -515,7 +515,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Bx::Value { // ZST are passed as operands and require special handling // because codegen_place() panics if Local is operand. - if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place { + if let mir::Place { + base: mir::PlaceBase::Local(index), + projection: None, + } = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::Array(_, n) = op.layout.ty.sty { let n = n.unwrap_usize(bx.cx().tcx()); @@ -524,8 +527,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } // use common size calculation for non zero-sized types - let cg_value = self.codegen_place(bx, place); - return cg_value.len(bx.cx()); + let cg_value = self.codegen_place(bx, &place.as_place_ref()); + cg_value.len(bx.cx()) } pub fn codegen_scalar_binop( diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 750b2f5b1a50f..499cda1cf8449 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -17,7 +17,10 @@ impl<'a, 'tcx, 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::Base(mir::PlaceBase::Local(index)) = *place { + if let mir::Place { + base: mir::PlaceBase::Local(index), + projection: None, + } = *place { match self.locals[index] { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) @@ -43,12 +46,12 @@ impl<'a, 'tcx, 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.as_place_ref()); self.codegen_rvalue(bx, cg_dest, rvalue) } } mir::StatementKind::SetDiscriminant{ref place, variant_index} => { - self.codegen_place(&mut bx, place) + self.codegen_place(&mut bx, &place.as_place_ref()) .codegen_set_discr(&mut bx, variant_index); bx } @@ -70,7 +73,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::StatementKind::InlineAsm(ref asm) => { let outputs = asm.outputs.iter().map(|output| { - self.codegen_place(&mut bx, output) + self.codegen_place(&mut bx, &output.as_place_ref()) }).collect(); let input_vals = asm.inputs.iter() diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 40d8173ce400a..c9e6e7f70a2b4 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx); - if let Some(local) = borrowed_place.base_local() { + if let mir::PlaceBase::Local(local) = borrowed_place.base { self.local_map.entry(local).or_default().insert(idx); } } @@ -315,7 +315,10 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { // TEMP = &foo // // so extract `temp`. - let temp = if let &mir::Place::Base(mir::PlaceBase::Local(temp)) = assigned_place { + let temp = if let &mir::Place { + base: mir::PlaceBase::Local(temp), + projection: None, + } = assigned_place { temp } else { span_bug!( diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 8986e87627e5e..95fc22dc5eb76 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -2,7 +2,7 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local, - LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, + LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::ty::{self, Ty}; @@ -48,7 +48,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span), + (moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span), mpi: MovePathIndex, ) { debug!( @@ -72,9 +72,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .collect(); if move_out_indices.is_empty() { - let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap(); + let root_place = self + .prefixes(used_place, PrefixSet::All) + .last() + .unwrap(); - if self.uninitialized_error_reported.contains(root_place) { + if self.uninitialized_error_reported.contains(&root_place) { debug!( "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", root_place @@ -82,7 +85,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; } - self.uninitialized_error_reported.insert(root_place.clone()); + self.uninitialized_error_reported.insert(root_place); let item_msg = match self.describe_place_with_options(used_place, IncludingDowncast(true)) { @@ -105,7 +108,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.buffer(&mut self.errors_buffer); } else { if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) { - if self.prefixes(&reported_place, PrefixSet::All) + if self.prefixes(*reported_place, PrefixSet::All) .any(|p| p == used_place) { debug!( @@ -123,7 +126,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span, desired_action.as_noun(), msg, - self.describe_place_with_options(&moved_place, IncludingDowncast(true)), + self.describe_place_with_options(moved_place, IncludingDowncast(true)), ); self.add_moved_or_invoked_closure_note( @@ -136,13 +139,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let is_partial_move = move_site_vec.iter().any(|move_site| { let move_out = self.move_data.moves[(*move_site).moi]; let moved_place = &self.move_data.move_paths[move_out.path].place; - used_place != moved_place && used_place.is_prefix_of(moved_place) + used_place != moved_place.as_place_ref() + && used_place.is_prefix_of(moved_place.as_place_ref()) }); for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; let moved_place = &self.move_data.move_paths[move_out.path].place; - let move_spans = self.move_spans(moved_place, move_out.source); + let move_spans = self.move_spans(moved_place.as_place_ref(), move_out.source); let move_span = move_spans.args_or_use(); let move_msg = if move_spans.for_closure() { @@ -200,7 +204,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - let ty = used_place.ty(self.body, self.infcx.tcx).ty; + let ty = + Place::ty_from(used_place.base, used_place.projection, self.body, self.infcx.tcx) + .ty; let needs_note = match ty.sty { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck_tables_of(id); @@ -216,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let place = &self.move_data.move_paths[mpi].place; let ty = place.ty(self.body, self.infcx.tcx).ty; - let opt_name = self.describe_place_with_options(place, IncludingDowncast(true)); + let opt_name = + self.describe_place_with_options(place.as_place_ref(), IncludingDowncast(true)); let note_msg = match opt_name { Some(ref name) => format!("`{}`", name), None => "value".to_owned(), @@ -232,7 +239,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - let span = if let Place::Base(PlaceBase::Local(local)) = place { + let span = if let Place { + base: PlaceBase::Local(local), + projection: None, + } = place { let decl = &self.body.local_decls[*local]; Some(decl.source_info.span) } else { @@ -247,7 +257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } if let Some((_, mut old_err)) = self.move_error_reported - .insert(move_out_indices, (used_place.clone(), err)) + .insert(move_out_indices, (used_place, err)) { // Cancel the old error so it doesn't ICE. old_err.cancel(); @@ -265,11 +275,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}", location, place, span, borrow ); - let value_msg = match self.describe_place(place) { + let value_msg = match self.describe_place(place.as_place_ref()) { Some(name) => format!("`{}`", name), None => "value".to_owned(), }; - let borrow_msg = match self.describe_place(&borrow.borrowed_place) { + let borrow_msg = match self.describe_place(borrow.borrowed_place.as_place_ref()) { Some(name) => format!("`{}`", name), None => "value".to_owned(), }; @@ -277,12 +287,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); - let move_spans = self.move_spans(place, location); + let move_spans = self.move_spans(place.as_place_ref(), location); let span = move_spans.args_or_use(); let mut err = self.cannot_move_when_borrowed( span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()), ); err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); err.span_label(span, format!("move out of {} occurs here", value_msg)); @@ -316,20 +326,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Conflicting borrows are reported separately, so only check for move // captures. - let use_spans = self.move_spans(place, location); + let use_spans = self.move_spans(place.as_place_ref(), location); let span = use_spans.var_or_use(); let mut err = self.cannot_use_when_mutably_borrowed( span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()), borrow_span, - &self.describe_place(&borrow.borrowed_place) + &self.describe_place(borrow.borrowed_place.as_place_ref()) .unwrap_or_else(|| "_".to_owned()), ); borrow_spans.var_span_label(&mut err, { let place = &borrow.borrowed_place; - let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned()); + let desc_place = + self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()); format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()) }); @@ -506,7 +517,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } else { let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_place(borrow_place) + let borrow_place_desc = self.describe_place(borrow_place.as_place_ref()) .unwrap_or_else(|| "_".to_owned()); issued_spans.var_span_label( &mut err, @@ -575,8 +586,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> (String, String, String, String) { // Define a small closure that we can use to check if the type of a place // is a union. - let union_ty = |place: &Place<'tcx>| -> Option> { - let ty = place.ty(self.body, self.infcx.tcx).ty; + let union_ty = |place_base, place_projection| { + let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty; ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) }; let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned()); @@ -595,13 +606,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // field access to a union. If we find that, then we will keep the place of the // union being accessed and the field that was being accessed so we can check the // second borrowed place for the same union and a access to a different field. - let mut current = first_borrowed_place; - while let Place::Projection(box Projection { base, elem }) = current { + let Place { + base, + projection, + } = first_borrowed_place; + + let mut current = projection; + + while let Some(box Projection { base: base_proj, elem }) = current { match elem { - ProjectionElem::Field(field, _) if union_ty(base).is_some() => { - return Some((base, field)); + ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => { + return Some((PlaceRef { + base: base, + projection: base_proj, + }, field)); }, - _ => current = base, + _ => current = base_proj, } } None @@ -609,22 +629,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .and_then(|(target_base, target_field)| { // With the place of a union and a field access into it, we traverse the second // borrowed place and look for a access to a different field of the same union. - let mut current = second_borrowed_place; - while let Place::Projection(box Projection { base, elem }) = current { + let Place { + base, + projection, + } = second_borrowed_place; + + let mut current = projection; + + while let Some(box Projection { base: proj_base, elem }) = current { if let ProjectionElem::Field(field, _) = elem { - if let Some(union_ty) = union_ty(base) { - if field != target_field && base == target_base { + if let Some(union_ty) = union_ty(base, proj_base) { + if field != target_field + && base == target_base.base + && proj_base == target_base.projection { + // FIXME when we avoid clone reuse describe_place closure + let describe_base_place = self.describe_place(PlaceRef { + base: base, + projection: proj_base, + }).unwrap_or_else(|| "_".to_owned()); + return Some(( - describe_place(base), - describe_place(first_borrowed_place), - describe_place(second_borrowed_place), + describe_base_place, + describe_place(first_borrowed_place.as_place_ref()), + describe_place(second_borrowed_place.as_place_ref()), union_ty.to_string(), )); } } } - current = base; + current = proj_base; } None }) @@ -632,7 +666,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If we didn't find a field access into a union, or both places match, then // only return the description of the first place. ( - describe_place(first_borrowed_place), + describe_place(first_borrowed_place.as_place_ref()), "".to_string(), "".to_string(), "".to_string(), @@ -663,20 +697,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); let drop_span = place_span.1; - let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) + let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(), PrefixSet::All) .last() .unwrap(); let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.var_or_use(); - let proper_span = match *root_place { - Place::Base(PlaceBase::Local(local)) => self.body.local_decls[local].source_info.span, + assert!(root_place.projection.is_none()); + let proper_span = match root_place.base { + PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span, _ => drop_span, }; if self.access_place_error_reported - .contains(&(root_place.clone(), borrow_span)) + .contains(&(Place { + base: root_place.base.clone(), + projection: root_place.projection.clone(), + }, borrow_span)) { debug!( "suppressing access_place error when borrow doesn't live long enough for {:?}", @@ -686,16 +724,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } self.access_place_error_reported - .insert((root_place.clone(), borrow_span)); + .insert((Place { + base: root_place.base.clone(), + projection: root_place.projection.clone(), + }, borrow_span)); if let StorageDeadOrDrop::Destructor(dropped_ty) = - self.classify_drop_access_kind(&borrow.borrowed_place) + self.classify_drop_access_kind(borrow.borrowed_place.as_place_ref()) { // If a borrow of path `B` conflicts with drop of `D` (and // 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) { + if !borrow.borrowed_place.as_place_ref().is_prefix_of(place_span.0.as_place_ref()) { self.report_borrow_conflicts_with_destructor( location, borrow, place_span, kind, dropped_ty, ); @@ -703,7 +744,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - let place_desc = self.describe_place(&borrow.borrowed_place); + let place_desc = self.describe_place(borrow.borrowed_place.as_place_ref()); let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place); @@ -910,12 +951,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_borrow_across_destructor(borrow_span); - let what_was_dropped = match self.describe_place(place) { + let what_was_dropped = match self.describe_place(place.as_place_ref()) { Some(name) => format!("`{}`", name.as_str()), None => String::from("temporary value"), }; - let label = match self.describe_place(&borrow.borrowed_place) { + let label = match self.describe_place(borrow.borrowed_place.as_place_ref()) { Some(borrowed) => format!( "here, drop of {D} needs exclusive access to `{B}`, \ because the type `{T}` implements the `Drop` trait", @@ -1061,7 +1102,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let (place_desc, note) = if let Some(place_desc) = opt_place_desc { let local_kind = match borrow.borrowed_place { - Place::Base(PlaceBase::Local(local)) => { + Place { + base: PlaceBase::Local(local), + projection: None, + } => { match self.body.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Temp => bug!("temporary or return pointer with a name"), @@ -1083,15 +1127,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("`{}` is borrowed here", place_desc), ) } else { - let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) + let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(), + PrefixSet::All) .last() .unwrap(); - let local = if let Place::Base(PlaceBase::Local(local)) = *root_place { + let local = if let PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } = root_place { local } else { bug!("try_report_cannot_return_reference_to_local: not a local") }; - match self.body.local_kind(local) { + match self.body.local_kind(*local) { LocalKind::ReturnPointer | LocalKind::Temp => { ( "temporary value".to_string(), @@ -1342,7 +1390,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_mutate_in_match_guard( span, loan_span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()), "assign", ); loan_spans.var_span_label( @@ -1358,7 +1406,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_assign_to_borrowed( span, loan_span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + &self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()), ); loan_spans.var_span_label( @@ -1385,7 +1433,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { assigned_span: Span, err_place: &Place<'tcx>, ) { - let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place { + let (from_arg, local_decl) = if let Place { + base: PlaceBase::Local(local), + projection: None, + } = *err_place { if let LocalKind::Arg = self.body.local_kind(local) { (true, Some(&self.body.local_decls[local])) } else { @@ -1415,8 +1466,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_user_variable: None, .. }) - | None => (self.describe_place(place), assigned_span), - Some(decl) => (self.describe_place(err_place), decl.source_info.span), + | None => (self.describe_place(place.as_place_ref()), assigned_span), + Some(decl) => (self.describe_place(err_place.as_place_ref()), decl.source_info.span), }; let mut err = self.cannot_reassign_immutable( @@ -1454,21 +1505,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.buffer(&mut self.errors_buffer); } - fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> { + fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> { let tcx = self.infcx.tcx; - match place { - Place::Base(PlaceBase::Local(_)) | - Place::Base(PlaceBase::Static(_)) => { + match place.projection { + None => { StorageDeadOrDrop::LocalStorageDead } - Place::Projection(box Projection { base, elem }) => { - let base_access = self.classify_drop_access_kind(base); + Some(box Projection { ref base, ref elem }) => { + let base_access = self.classify_drop_access_kind(PlaceRef { + base: place.base, + projection: base, + }); match elem { ProjectionElem::Deref => match base_access { StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - base.ty(self.body, tcx).ty.is_box(), + Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1476,7 +1529,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = base.ty(self.body, tcx).ty; + let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty; match base_ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor @@ -1543,8 +1596,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); // Check that the initial assignment of the reserve location is into a temporary. let mut target = *match reservation { - Place::Base(PlaceBase::Local(local)) - if self.body.local_kind(*local) == LocalKind::Temp => local, + Place { + base: PlaceBase::Local(local), + projection: None, + } if self.body.local_kind(*local) == LocalKind::Temp => local, _ => return None, }; @@ -1557,7 +1612,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { target, stmt ); if let StatementKind::Assign( - Place::Base(PlaceBase::Local(assigned_to)), + Place { + base: PlaceBase::Local(assigned_to), + projection: None, + }, box rvalue ) = &stmt.kind { debug!( @@ -1682,7 +1740,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { target, terminator ); if let TerminatorKind::Call { - destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)), + destination: Some((Place { + base: PlaceBase::Local(assigned_to), + projection: None, + }, _)), args, .. } = &terminator.kind diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 5f61ed151c0d6..156897aedb70a 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -3,8 +3,8 @@ use rustc::hir::def::Namespace; use rustc::hir::def_id::DefId; use rustc::mir::{ AggregateKind, Constant, Field, Local, LocalKind, Location, Operand, - Place, PlaceBase, ProjectionElem, Rvalue, Statement, StatementKind, Static, - StaticKind, Terminator, TerminatorKind, + Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, + Static, StaticKind, Terminator, TerminatorKind, }; use rustc::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc::ty::layout::VariantIdx; @@ -34,7 +34,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub(super) fn add_moved_or_invoked_closure_note( &self, location: Location, - place: &Place<'tcx>, + place: PlaceRef<'cx, 'tcx>, diag: &mut DiagnosticBuilder<'_>, ) { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); @@ -121,8 +121,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// End-user visible description of `place` if one can be found. If the /// place is a temporary for instance, None will be returned. - pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option { - self.describe_place_with_options(place, IncludingDowncast(false)) + pub(super) fn describe_place(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option { + self.describe_place_with_options(place_ref, IncludingDowncast(false)) } /// End-user visible description of `place` if one can be found. If the @@ -131,7 +131,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// `Downcast` and `IncludingDowncast` is true pub(super) fn describe_place_with_options( &self, - place: &Place<'tcx>, + place: PlaceRef<'cx, 'tcx>, including_downcast: IncludingDowncast, ) -> Option { let mut buf = String::new(); @@ -144,22 +144,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Appends end-user visible description of `place` to `buf`. fn append_place_to_string( &self, - place: &Place<'tcx>, + place: PlaceRef<'cx, 'tcx>, buf: &mut String, mut autoderef: bool, including_downcast: &IncludingDowncast, ) -> Result<(), ()> { - match *place { - Place::Base(PlaceBase::Local(local)) => { - self.append_local_to_string(local, buf)?; + match place { + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } => { + self.append_local_to_string(*local, buf)?; } - Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => { + PlaceRef { + base: + PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }), + projection: None, + } => { buf.push_str("promoted"); } - Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => { - buf.push_str(&self.infcx.tcx.item_name(def_id).to_string()); + PlaceRef { + base: + PlaceBase::Static(box Static { + kind: StaticKind::Static(def_id), + .. + }), + projection: None, + } => { + buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string()); } - Place::Projection(ref proj) => { + PlaceRef { + ref base, + projection: Some(ref proj), + } => { match proj.elem { ProjectionElem::Deref => { let upvar_field_projection = @@ -174,43 +194,66 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { if autoderef { + // FIXME turn this recursion into iteration self.append_place_to_string( - &proj.base, + PlaceRef { + base: &base, + projection: &proj.base, + }, buf, autoderef, &including_downcast, )?; - } else if let Place::Base(PlaceBase::Local(local)) = proj.base { - if self.body.local_decls[local].is_ref_for_guard() { - self.append_place_to_string( - &proj.base, - buf, - autoderef, - &including_downcast, - )?; - } else { - buf.push_str(&"*"); - self.append_place_to_string( - &proj.base, - buf, - autoderef, - &including_downcast, - )?; - } } else { - buf.push_str(&"*"); - self.append_place_to_string( - &proj.base, - buf, - autoderef, - &including_downcast, - )?; + match (&proj.base, base) { + (None, PlaceBase::Local(local)) => { + if self.body.local_decls[*local].is_ref_for_guard() { + self.append_place_to_string( + PlaceRef { + base: &base, + projection: &proj.base, + }, + buf, + autoderef, + &including_downcast, + )?; + } else { + // FIXME deduplicate this and the _ => body below + buf.push_str(&"*"); + self.append_place_to_string( + PlaceRef { + base: &base, + projection: &proj.base, + }, + buf, + autoderef, + &including_downcast, + )?; + } + } + + _ => { + buf.push_str(&"*"); + self.append_place_to_string( + PlaceRef { + base: &base, + projection: &proj.base, + }, + buf, + autoderef, + &including_downcast, + )?; + } + } } } } ProjectionElem::Downcast(..) => { self.append_place_to_string( - &proj.base, + PlaceRef { + base: &base, + projection: &proj.base, + }, buf, autoderef, &including_downcast, @@ -229,9 +272,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let name = self.upvars[var_index].name.to_string(); buf.push_str(&name); } else { - let field_name = self.describe_field(&proj.base, field); + let field_name = self.describe_field(PlaceRef { + base: base, + projection: &proj.base, + }, field); self.append_place_to_string( - &proj.base, + PlaceRef { + base: &base, + projection: &proj.base, + }, buf, autoderef, &including_downcast, @@ -243,7 +292,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef = true; self.append_place_to_string( - &proj.base, + PlaceRef { + base: &base, + projection: &proj.base, + }, buf, autoderef, &including_downcast, @@ -260,7 +312,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 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, + PlaceRef { + base: &base, + projection: &proj.base, + }, buf, autoderef, &including_downcast, @@ -288,18 +343,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, base: &Place<'tcx>, field: Field) -> String { - match *base { - Place::Base(PlaceBase::Local(local)) => { - let local = &self.body.local_decls[local]; + fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String { + // FIXME Place2 Make this work iteratively + match place { + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } => { + let local = &self.body.local_decls[*local]; self.describe_field_from_ty(&local.ty, field, None) } - Place::Base(PlaceBase::Static(ref static_)) => + PlaceRef { + base: PlaceBase::Static(static_), + projection: None, + } => self.describe_field_from_ty(&static_.ty, field, None), - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Deref => self.describe_field(&proj.base, field), + PlaceRef { + base, + projection: Some(proj), + } => match proj.elem { + ProjectionElem::Deref => self.describe_field(PlaceRef { + base, + projection: &proj.base, + }, field), ProjectionElem::Downcast(_, variant_index) => { - let base_ty = base.ty(self.body, self.infcx.tcx).ty; + let base_ty = + Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty; self.describe_field_from_ty(&base_ty, field, Some(variant_index)) } ProjectionElem::Field(_, field_type) => { @@ -308,7 +377,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - self.describe_field(&proj.base, field) + self.describe_field(PlaceRef { + base, + projection: &proj.base, + }, field) } }, } @@ -365,10 +437,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// Checks if a place is a thread-local static. - pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool { - if let Place::Base( - PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) - ) = place { + pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool { + if let PlaceRef { + base: PlaceBase::Static(box Static { + kind: StaticKind::Static(def_id), + .. + }), + projection: None, + } = place_ref { let attrs = self.infcx.tcx.get_attrs(*def_id); let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); @@ -405,7 +481,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub(super) fn borrowed_content_source( &self, - deref_base: &Place<'tcx>, + deref_base: PlaceRef<'cx, 'tcx>, ) -> BorrowedContentSource<'tcx> { let tcx = self.infcx.tcx; @@ -457,7 +533,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If we didn't find an overloaded deref or index, then assume it's a // built in deref and check the type of the base. - let base_ty = deref_base.ty(self.body, tcx).ty; + let base_ty = Place::ty_from(deref_base.base, deref_base.projection, self.body, tcx).ty; if base_ty.is_unsafe_ptr() { BorrowedContentSource::DerefRawPointer } else if base_ty.is_mutable_pointer() { @@ -700,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( &self, - moved_place: &Place<'tcx>, // Could also be an upvar. + moved_place: PlaceRef<'cx, 'tcx>, // Could also be an upvar. location: Location, ) -> UseSpans { use self::UseSpans::*; @@ -750,7 +826,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .get(location.statement_index) { Some(&Statement { - kind: StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _), + kind: StatementKind::Assign(Place { + base: PlaceBase::Local(local), + projection: None, + }, _), .. }) => local, _ => return OtherUse(use_span), @@ -776,7 +855,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id, is_generator, places ); if let Some((args_span, var_span)) = self.closure_span( - *def_id, &Place::from(target), places + *def_id, Place::from(target).as_place_ref(), places ) { return ClosureUse { is_generator, @@ -800,7 +879,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn closure_span( &self, def_id: DefId, - target_place: &Place<'tcx>, + target_place: PlaceRef<'cx, 'tcx>, places: &Vec>, ) -> Option<(Span, Span)> { debug!( @@ -816,7 +895,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { match place { Operand::Copy(place) | - Operand::Move(place) if target_place == place => { + Operand::Move(place) if target_place == place.as_place_ref() => { debug!("closure_span: found captured local {:?}", place); return Some((*args_span, upvar.span)); }, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5851cd8178878..cfc7e77f4e5a8 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -10,9 +10,8 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; use rustc::middle::borrowck::SignalledError; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ - ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, Static, - - StaticKind + ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef, + Static, StaticKind }; use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; @@ -474,10 +473,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary /// when errors in the map are being re-added to the error buffer so that errors with the /// same primary span come out in a consistent order. - move_error_reported: BTreeMap, (Place<'tcx>, DiagnosticBuilder<'cx>)>, + move_error_reported: BTreeMap, (PlaceRef<'cx, 'tcx>, DiagnosticBuilder<'cx>)>, /// This field keeps track of errors reported in the checking of uninitialized variables, /// so that we don't report seemingly duplicate errors. - uninitialized_error_reported: FxHashSet>, + uninitialized_error_reported: FxHashSet>, /// Errors to be reported buffer errors_buffer: Vec, /// This field keeps track of all the local variables that are declared mut and are mutated. @@ -520,7 +519,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx fn visit_statement_entry( &mut self, location: Location, - stmt: &Statement<'tcx>, + stmt: &'cx Statement<'tcx>, flow_state: &Self::FlowState, ) { debug!( @@ -561,7 +560,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, - (place, span), + (place.as_place_ref(), span), flow_state, ); } @@ -592,7 +591,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, - (output, o.span), + (output.as_place_ref(), o.span), flow_state, ); } else { @@ -631,7 +630,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx fn visit_terminator_entry( &mut self, location: Location, - term: &Terminator<'tcx>, + term: &'cx Terminator<'tcx>, flow_state: &Self::FlowState, ) { let loc = location; @@ -890,7 +889,8 @@ enum InitializationRequiringAction { } struct RootPlace<'d, 'tcx> { - place: &'d Place<'tcx>, + place_base: &'d PlaceBase<'tcx>, + place_projection: &'d Option>>, is_local_mutation_allowed: LocalMutationIsAllowed, } @@ -1143,7 +1143,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn mutate_place( &mut self, location: Location, - place_span: (&Place<'tcx>, Span), + place_span: (&'cx Place<'tcx>, Span), kind: AccessDepth, mode: MutateMode, flow_state: &Flows<'cx, 'tcx>, @@ -1154,7 +1154,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Update, - place_span, + (place_span.0.as_place_ref(), place_span.1), flow_state, ); } @@ -1166,12 +1166,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Special case: you can assign a immutable local variable // (e.g., `x = ...`) so long as it has never been initialized // before (at this point in the flow). - if let &Place::Base(PlaceBase::Local(local)) = place_span.0 { - if let Mutability::Not = self.body.local_decls[local].mutability { + if let Place { + base: PlaceBase::Local(local), + projection: None, + } = place_span.0 { + if let Mutability::Not = self.body.local_decls[*local].mutability { // check for reassignments to immutable local variables self.check_if_reassignment_to_immutable_state( location, - local, + *local, place_span, flow_state, ); @@ -1192,7 +1195,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn consume_rvalue( &mut self, location: Location, - (rvalue, span): (&Rvalue<'tcx>, Span), + (rvalue, span): (&'cx Rvalue<'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { match *rvalue { @@ -1229,7 +1232,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_path_or_subpath_is_moved( location, action, - (place, span), + (place.as_place_ref(), span), flow_state, ); } @@ -1257,7 +1260,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, - (place, span), + (place.as_place_ref(), span), flow_state, ); } @@ -1305,16 +1308,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| { - match *place { - Place::Projection { .. } => { - if let Some(field) = this.is_upvar_field_projection(place) { - this.used_mut_upvars.push(field); - } - } - Place::Base(PlaceBase::Local(local)) => { - this.used_mut.insert(local); + if place.projection.is_some() { + if let Some(field) = this.is_upvar_field_projection(place.as_place_ref()) { + this.used_mut_upvars.push(field); } - Place::Base(PlaceBase::Static(_)) => {} + } else if let PlaceBase::Local(local) = place.base { + this.used_mut.insert(local); } }; @@ -1322,10 +1321,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // captures of a closure are copied/moved directly // when generating MIR. match *operand { - Operand::Move(Place::Base(PlaceBase::Local(local))) - | Operand::Copy(Place::Base(PlaceBase::Local(local))) - if self.body.local_decls[local].is_user_variable.is_none() => - { + Operand::Move(Place { + base: PlaceBase::Local(local), + projection: None, + }) | + Operand::Copy(Place { + base: PlaceBase::Local(local), + projection: None, + }) if self.body.local_decls[local].is_user_variable.is_none() => { if self.body.local_decls[local].ty.is_mutable_pointer() { // The variable will be marked as mutable by the borrow. return; @@ -1379,7 +1382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn consume_operand( &mut self, location: Location, - (operand, span): (&Operand<'tcx>, Span), + (operand, span): (&'cx Operand<'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { match *operand { @@ -1398,7 +1401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, - (place, span), + (place.as_place_ref(), span), flow_state, ); } @@ -1416,7 +1419,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, - (place, span), + (place.as_place_ref(), span), flow_state, ); } @@ -1434,30 +1437,35 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) { debug!("check_for_invalidation_at_exit({:?})", borrow); let place = &borrow.borrowed_place; - let root_place = self.prefixes(place, PrefixSet::All).last().unwrap(); + let root_place = self.prefixes(place.as_place_ref(), PrefixSet::All).last().unwrap(); // FIXME(nll-rfc#40): do more precise destructor tracking here. For now // we just know that all locals are dropped at function exit (otherwise // we'll have a memory leak) and assume that all statics have a destructor. // // FIXME: allow thread-locals to borrow other thread locals? - let (might_be_alive, will_be_dropped) = match root_place { - Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => { + + assert!(root_place.projection.is_none()); + let (might_be_alive, will_be_dropped) = match root_place.base { + PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }) => { (true, false) } - Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(_), .. })) => { + PlaceBase::Static(box Static { + kind: StaticKind::Static(_), + .. + }) => { // Thread-locals might be dropped after the function exits, but // "true" statics will never be. - (true, self.is_place_thread_local(&root_place)) + (true, self.is_place_thread_local(root_place)) } - Place::Base(PlaceBase::Local(_)) => { + PlaceBase::Local(_) => { // Locals are always dropped at function exit, and if they // have a destructor it would've been called already. (false, self.locals_are_invalidated_at_exit) } - Place::Projection(..) => { - bug!("root of {:?} is a projection ({:?})?", place, root_place) - } }; if !will_be_dropped { @@ -1563,7 +1571,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - place_span: (&Place<'tcx>, Span), + place_span: (PlaceRef<'cx, 'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1631,7 +1639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - place_span: (&Place<'tcx>, Span), + place_span: (PlaceRef<'cx, 'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1686,25 +1694,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// An Err result includes a tag indicated why the search failed. /// Currently this can only occur if the place is built off of a /// static variable, as we do not track those in the MoveData. - fn move_path_closest_to<'a>( + fn move_path_closest_to( &mut self, - place: &'a Place<'tcx>, - ) -> Result<(&'a Place<'tcx>, MovePathIndex), NoMovePathFound> where 'cx: 'a { - let mut last_prefix = place; + place: PlaceRef<'cx, 'tcx>, + ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> { + let mut last_prefix = place.base; + for prefix in self.prefixes(place, PrefixSet::All) { if let Some(mpi) = self.move_path_for_place(prefix) { return Ok((prefix, mpi)); } - last_prefix = prefix; + + last_prefix = prefix.base; } - match *last_prefix { - Place::Base(PlaceBase::Local(_)) => panic!("should have move path for every Local"), - Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"), - Place::Base(PlaceBase::Static(_)) => Err(NoMovePathFound::ReachedStatic), + + match last_prefix { + PlaceBase::Local(_) => panic!("should have move path for every Local"), + PlaceBase::Static(_) => Err(NoMovePathFound::ReachedStatic), } } - fn move_path_for_place(&mut self, place: &Place<'tcx>) -> Option { + fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option { // If returns None, then there is no move path corresponding // to a direct owner of `place` (which means there is nothing // that borrowck tracks for its analysis). @@ -1718,94 +1728,97 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn check_if_assigned_path_is_moved( &mut self, location: Location, - (place, span): (&Place<'tcx>, Span), + (place, span): (&'cx Place<'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); // recur down place; dispatch to external checks when necessary - let mut place = place; - loop { - match *place { - Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => { - // assigning to `x` does not require `x` be initialized. + let mut place_projection = &place.projection; + + // None case => assigning to `x` does not require `x` be initialized. + while let Some(proj) = place_projection { + let Projection { ref base, ref elem } = **proj; + match *elem { + ProjectionElem::Index(_/*operand*/) | + ProjectionElem::ConstantIndex { .. } | + // assigning to P[i] requires P to be valid. + ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => + // assigning to (P->variant) is okay if assigning to `P` is okay + // + // FIXME: is this true even if P is a adt with a dtor? + { } + + // assigning to (*P) requires P to be initialized + ProjectionElem::Deref => { + self.check_if_full_path_is_moved( + location, InitializationRequiringAction::Use, + (PlaceRef { + base: &place.base, + projection: base, + }, span), flow_state); + // (base initialized; no need to + // recur further) break; } - Place::Projection(ref proj) => { - let Projection { ref base, ref elem } = **proj; - match *elem { - ProjectionElem::Index(_/*operand*/) | - ProjectionElem::ConstantIndex { .. } | - // assigning to P[i] requires P to be valid. - ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => - // assigning to (P->variant) is okay if assigning to `P` is okay - // - // FIXME: is this true even if P is a adt with a dtor? - { } - - // assigning to (*P) requires P to be initialized - ProjectionElem::Deref => { - self.check_if_full_path_is_moved( - location, InitializationRequiringAction::Use, - (base, span), flow_state); + + ProjectionElem::Subslice { .. } => { + panic!("we don't allow assignments to subslices, location: {:?}", + location); + } + + ProjectionElem::Field(..) => { + // if type of `P` has a dtor, then + // assigning to `P.f` requires `P` itself + // be already initialized + let tcx = self.infcx.tcx; + let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty; + match base_ty.sty { + ty::Adt(def, _) if def.has_dtor(tcx) => { + self.check_if_path_or_subpath_is_moved( + location, InitializationRequiringAction::Assignment, + (PlaceRef { + base: &place.base, + projection: base, + }, span), flow_state); + // (base initialized; no need to // recur further) break; } - ProjectionElem::Subslice { .. } => { - panic!("we don't allow assignments to subslices, location: {:?}", - location); - } - - ProjectionElem::Field(..) => { - // if type of `P` has a dtor, then - // assigning to `P.f` requires `P` itself - // be already initialized - let tcx = self.infcx.tcx; - match base.ty(self.body, tcx).ty.sty { - ty::Adt(def, _) if def.has_dtor(tcx) => { - self.check_if_path_or_subpath_is_moved( - location, InitializationRequiringAction::Assignment, - (base, span), flow_state); - - // (base initialized; no need to - // recur further) - break; - } - - - // Once `let s; s.x = V; read(s.x);`, - // is allowed, remove this match arm. - ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, location, base, span, flow_state); - - if let Some(local) = place.base_local() { - // rust-lang/rust#21232, - // #54499, #54986: during - // period where we reject - // partial initialization, do - // not complain about - // unnecessary `mut` on an - // attempt to do a partial - // initialization. - self.used_mut.insert(local); - } - } - - _ => {} + // Once `let s; s.x = V; read(s.x);`, + // is allowed, remove this match arm. + ty::Adt(..) | ty::Tuple(..) => { + check_parent_of_field(self, location, PlaceRef { + base: &place.base, + projection: base, + }, span, flow_state); + + if let PlaceBase::Local(local) = place.base { + // rust-lang/rust#21232, + // #54499, #54986: during + // period where we reject + // partial initialization, do + // not complain about + // unnecessary `mut` on an + // attempt to do a partial + // initialization. + self.used_mut.insert(local); } } - } - place = base; + _ => {} + } } } + + place_projection = base; } fn check_parent_of_field<'cx, 'tcx>( this: &mut MirBorrowckCtxt<'cx, 'tcx>, location: Location, - base: &Place<'tcx>, + base: PlaceRef<'cx, 'tcx>, span: Span, flow_state: &Flows<'cx, 'tcx>, ) { @@ -1866,7 +1879,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, '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::Adt(def, _) = base.ty(this.body, tcx).ty.sty { + if let ty::Adt(def, _) = + Place::ty_from(base.base, base.projection, this.body, tcx).ty.sty + { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of( @@ -1911,7 +1926,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, '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 previously_initialized = if let PlaceBase::Local(local) = place.base { self.is_local_ever_initialized(local, flow_state).is_some() } else { true @@ -1927,7 +1942,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { BorrowKind::Mut { .. } => is_local_mutation_allowed, BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; - match self.is_mutable(place, is_local_mutation_allowed) { + match self.is_mutable(&place.base, &place.projection, is_local_mutation_allowed) { Ok(root_place) => { self.add_used_mut(root_place, flow_state); return false; @@ -1939,7 +1954,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { - match self.is_mutable(place, is_local_mutation_allowed) { + match self.is_mutable(&place.base, &place.projection, is_local_mutation_allowed) { Ok(root_place) => { self.add_used_mut(root_place, flow_state); return false; @@ -1960,7 +1975,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => { if let (Err(_place_err), true) = ( - self.is_mutable(place, is_local_mutation_allowed), + self.is_mutable(&place.base, &place.projection, is_local_mutation_allowed), self.errors_buffer.is_empty() ) { if self.infcx.tcx.migrate_borrowck() { @@ -1981,7 +1996,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.report_mutability_error( place, span, - _place_err, + PlaceRef { + base: _place_err.0, + projection: _place_err.1, + }, error_access, location, ); @@ -2015,7 +2033,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.report_mutability_error( place, span, - the_place_err, + PlaceRef { + base: the_place_err.0, + projection: the_place_err.1, + }, error_access, location, ); @@ -2044,7 +2065,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) { match root_place { RootPlace { - place: Place::Base(PlaceBase::Local(local)), + place_base: PlaceBase::Local(local), + place_projection: None, is_local_mutation_allowed, } => { // If the local may have been initialized, and it is now currently being @@ -2057,19 +2079,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } RootPlace { - place: _, + place_base: _, + place_projection: _, is_local_mutation_allowed: LocalMutationIsAllowed::Yes, } => {} RootPlace { - place: place @ Place::Projection(_), + place_base, + place_projection: place_projection @ Some(_), is_local_mutation_allowed: _, } => { - if let Some(field) = self.is_upvar_field_projection(place) { + if let Some(field) = self.is_upvar_field_projection(PlaceRef { + base: &place_base, + projection: &place_projection, + }) { self.used_mut_upvars.push(field); } } RootPlace { - place: Place::Base(PlaceBase::Static(..)), + place_base: PlaceBase::Static(..), + place_projection: None, is_local_mutation_allowed: _, } => {} } @@ -2079,62 +2107,78 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Returns the root place if the place passed in is a projection. fn is_mutable<'d>( &self, - place: &'d Place<'tcx>, + place_base: &'d PlaceBase<'tcx>, + place_projection: &'d Option>>, is_local_mutation_allowed: LocalMutationIsAllowed, - ) -> Result, &'d Place<'tcx>> { - match *place { - Place::Base(PlaceBase::Local(local)) => { - let local = &self.body.local_decls[local]; + ) -> Result, (&'d PlaceBase<'tcx>, &'d Option>>)> { + match (place_base, place_projection) { + (PlaceBase::Local(local), None) => { + let local = &self.body.local_decls[*local]; match local.mutability { Mutability::Not => match is_local_mutation_allowed { LocalMutationIsAllowed::Yes => Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed: LocalMutationIsAllowed::Yes, }), LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars, }), - LocalMutationIsAllowed::No => Err(place), + LocalMutationIsAllowed::No => Err((place_base, place_projection)), }, Mutability::Mut => Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed, }), } } // The rules for promotion are made by `qualify_consts`, there wouldn't even be a // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this - Place::Base(PlaceBase::Static(box Static{kind: StaticKind::Promoted(_), ..})) => + (PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }), None) => Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed, }), - Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => { - if !self.infcx.tcx.is_mutable_static(def_id) { - Err(place) + (PlaceBase::Static(box Static { + kind: StaticKind::Static(def_id), + .. + }), None) => { + if !self.infcx.tcx.is_mutable_static(*def_id) { + Err((place_base, place_projection)) } else { Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed, }) } } - Place::Projection(ref proj) => { + (_, Some(ref proj)) => { match proj.elem { ProjectionElem::Deref => { - let base_ty = proj.base.ty(self.body, self.infcx.tcx).ty; + let base_ty = + Place::ty_from(place_base, &proj.base, self.body, self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.sty { ty::Ref(_, _, mutbl) => { match mutbl { // Shared borrowed data is never mutable - hir::MutImmutable => Err(place), + hir::MutImmutable => Err((place_base, place_projection)), // Mutably borrowed data is mutable, but only if we have a // unique path to the `&mut` hir::MutMutable => { - let mode = match self.is_upvar_field_projection(place) { + let mode = match self.is_upvar_field_projection(PlaceRef { + base: &place_base, + projection: &place_projection, + }) { Some(field) if self.upvars[field.index()].by_ref => { @@ -2143,19 +2187,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => LocalMutationIsAllowed::Yes, }; - self.is_mutable(&proj.base, mode) + self.is_mutable(place_base, &proj.base, mode) } } } ty::RawPtr(tnm) => { match tnm.mutbl { // `*const` raw pointers are not mutable - hir::MutImmutable => Err(place), + hir::MutImmutable => Err((place_base, place_projection)), // `*mut` raw pointers are always mutable, regardless of // context. The users have to check by themselves. hir::MutMutable => { Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed, }) } @@ -2163,7 +2208,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } // `Box` owns its content, so mutable if its location is mutable _ if base_ty.is_box() => { - self.is_mutable(&proj.base, is_local_mutation_allowed) + self.is_mutable(place_base, &proj.base, is_local_mutation_allowed) } // Deref should only be for reference, pointers or boxes _ => bug!("Deref of unexpected type: {:?}", base_ty), @@ -2176,17 +2221,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..) => { - let upvar_field_projection = self.is_upvar_field_projection(place); + let upvar_field_projection = self.is_upvar_field_projection(PlaceRef { + base: &place_base, + projection: &place_projection, + }); if let Some(field) = upvar_field_projection { let upvar = &self.upvars[field.index()]; debug!( - "upvar.mutability={:?} local_mutation_is_allowed={:?} place={:?}", - upvar, is_local_mutation_allowed, place + "upvar.mutability={:?} local_mutation_is_allowed={:?} \ + place={:?} {:?}", + upvar, is_local_mutation_allowed, place_base, place_projection ); match (upvar.mutability, is_local_mutation_allowed) { (Mutability::Not, LocalMutationIsAllowed::No) | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => { - Err(place) + Err((place_base, place_projection)) } (Mutability::Not, LocalMutationIsAllowed::Yes) | (Mutability::Mut, _) => { @@ -2216,15 +2265,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // }); // } // ``` - let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?; + let _ = self.is_mutable(place_base, + &proj.base, + is_local_mutation_allowed)?; Ok(RootPlace { - place, + place_base, + place_projection, is_local_mutation_allowed, }) } } } else { - self.is_mutable(&proj.base, is_local_mutation_allowed) + self.is_mutable(place_base, &proj.base, is_local_mutation_allowed) } } } @@ -2236,33 +2288,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// 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(&self, place: &Place<'tcx>) -> Option { - let (place, by_ref) = if let Place::Projection(ref proj) = place { - if let ProjectionElem::Deref = proj.elem { - (&proj.base, true) - } else { - (place, false) - } - } else { - (place, false) - }; - - match place { - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _ty) => { - let tcx = self.infcx.tcx; - let base_ty = proj.base.ty(self.body, tcx).ty; + pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option { + let mut place_projection = place_ref.projection; + let mut by_ref = false; + + if let Some(box Projection { + base, + elem: ProjectionElem::Deref, + }) = place_projection { + place_projection = &base; + by_ref = true; + } - if (base_ty.is_closure() || base_ty.is_generator()) && - (!by_ref || self.upvars[field.index()].by_ref) - { - Some(field) - } else { - None - } - }, - _ => None, + match place_projection { + Some(box Projection { + base, + elem: ProjectionElem::Field(field, _ty), + }) => { + let tcx = self.infcx.tcx; + let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty; + + if (base_ty.is_closure() || base_ty.is_generator()) && + (!by_ref || self.upvars[field.index()].by_ref) { + Some(*field) + } else { + None + } } + _ => None, } } diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 5939adc5528d9..38653dc0e5e9b 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -91,7 +91,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // If that ever stops being the case, then the ever initialized // flow could be used. if let Some(StatementKind::Assign( - Place::Base(PlaceBase::Local(local)), + Place { + base: PlaceBase::Local(local), + projection: None, + }, box Rvalue::Use(Operand::Move(move_from)), )) = self.body.basic_blocks()[location.block] .statements @@ -128,7 +131,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - let move_spans = self.move_spans(&original_path, location); + let move_spans = self.move_spans(original_path.as_place_ref(), location); grouped_errors.push(GroupedMoveError::OtherIllegalMove { use_spans: move_spans, original_path, @@ -157,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let from_simple_let = match_place.is_none(); let match_place = match_place.as_ref().unwrap_or(move_from); - match self.move_data.rev_lookup.find(match_place) { + match self.move_data.rev_lookup.find(match_place.as_place_ref()) { // Error with the match place LookupResult::Parent(_) => { for ge in &mut *grouped_errors { @@ -189,7 +192,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } // Error with the pattern LookupResult::Exact(_) => { - let mpi = match self.move_data.rev_lookup.find(move_from) { + let mpi = match self.move_data.rev_lookup.find(move_from.as_place_ref()) { LookupResult::Parent(Some(mpi)) => mpi, // move_from should be a projection from match_place. _ => unreachable!("Probably not unreachable..."), @@ -239,7 +242,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; debug!("report: original_path={:?} span={:?}, kind={:?} \ original_path.is_upvar_field_projection={:?}", original_path, span, kind, - self.is_upvar_field_projection(original_path)); + self.is_upvar_field_projection(original_path.as_place_ref())); ( match kind { IllegalMoveOriginKind::Static => { @@ -273,20 +276,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { place: &Place<'tcx>, span: Span ) -> DiagnosticBuilder<'a> { - let mut base_static = place; - loop { - match base_static { - Place::Base(_) => break, - Place::Projection(box Projection { base, .. }) => base_static = base, + let description = if place.projection.is_none() { + format!("static item `{}`", self.describe_place(place.as_place_ref()).unwrap()) + } else { + let mut base_static = &place.projection; + while let Some(box Projection { base: Some(ref proj), .. }) = base_static { + base_static = &proj.base; } - } + let base_static = PlaceRef { + base: &place.base, + projection: base_static, + }; - let description = if let Place::Base(_) = place { - format!("static item `{}`", self.describe_place(place).unwrap()) - } else { format!( "`{:?}` as `{:?}` is a static item", - self.describe_place(place).unwrap(), + self.describe_place(place.as_place_ref()).unwrap(), self.describe_place(base_static).unwrap(), ) }; @@ -304,16 +308,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // borrow to provide feedback about why this // was a move rather than a copy. let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; - let upvar_field = self.prefixes(&move_place, PrefixSet::All) + let upvar_field = self.prefixes(move_place.as_place_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); - let deref_base = match deref_target_place { - Place::Projection(box Projection { base, elem: ProjectionElem::Deref }) => base, + let deref_base = match deref_target_place.projection { + Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef { + base: &deref_target_place.base, + projection: base, + }, _ => bug!("deref_target_place is not a deref projection"), }; - if let Place::Base(PlaceBase::Local(local)) = *deref_base { - let decl = &self.body.local_decls[local]; + if let PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } = deref_base { + let decl = &self.body.local_decls[*local]; if decl.is_ref_for_guard() { let mut err = self.cannot_move_out_of( span, @@ -353,9 +363,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_name = upvar.name; let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); - let place_name = self.describe_place(move_place).unwrap(); + let place_name = self.describe_place(move_place.as_place_ref()).unwrap(); - let place_description = if self.is_upvar_field_projection(move_place).is_some() { + let place_description = if self + .is_upvar_field_projection(move_place.as_place_ref()) + .is_some() + { format!("`{}`, a {}", place_name, capture_description) } else { format!( @@ -379,7 +392,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } _ => { let source = self.borrowed_content_source(deref_base); - match (self.describe_place(move_place), source.describe_for_named_place()) { + match ( + self.describe_place(move_place.as_place_ref()), + source.describe_for_named_place(), + ) { (Some(place_desc), Some(source_desc)) => { self.cannot_move_out_of( span, @@ -439,7 +455,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if binds_to.is_empty() { let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; - let place_desc = match self.describe_place(&move_from) { + let place_desc = match self.describe_place(move_from.as_place_ref()) { Some(desc) => format!("`{}`", desc), None => format!("value"), }; @@ -467,7 +483,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { let span = use_spans.var_or_use(); let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; - let place_desc = match self.describe_place(original_path) { + let place_desc = match self.describe_place(original_path.as_place_ref()) { Some(desc) => format!("`{}`", desc), None => format!("value"), }; diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 59a3354f9c52f..c424c06c41add 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -2,7 +2,9 @@ use core::unicode::property::Pattern_White_Space; use rustc::hir; use rustc::hir::Node; use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body}; -use rustc::mir::{Mutability, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind}; +use rustc::mir::{ + Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind +}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; @@ -25,7 +27,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &mut self, access_place: &Place<'tcx>, span: Span, - the_place_err: &Place<'tcx>, + the_place_err: PlaceRef<'cx, 'tcx>, error_access: AccessKind, location: Location, ) { @@ -40,13 +42,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let item_msg; let reason; let mut opt_source = None; - let access_place_desc = self.describe_place(access_place); + let access_place_desc = self.describe_place(access_place.as_place_ref()); debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); match the_place_err { - Place::Base(PlaceBase::Local(local)) => { + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } => { item_msg = format!("`{}`", access_place_desc.unwrap()); - if let Place::Base(PlaceBase::Local(_)) = access_place { + if let Place { + base: PlaceBase::Local(_), + projection: None, + } = access_place { reason = ", as it is not declared as mutable".to_string(); } else { let name = self.body.local_decls[*local] @@ -56,16 +64,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - Place::Projection(box Projection { - base, - elem: ProjectionElem::Field(upvar_index, _), - }) => { + PlaceRef { + base: _, + projection: + Some(box Projection { + base, + elem: ProjectionElem::Field(upvar_index, _), + }), + } => { debug_assert!(is_closure_or_generator( - base.ty(self.body, self.infcx.tcx).ty + Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); - if self.is_upvar_field_projection(access_place).is_some() { + if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { let name = self.upvars[upvar_index.index()].name; @@ -73,26 +85,38 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - Place::Projection(box Projection { - base, - elem: ProjectionElem::Deref, - }) => { - if *base == Place::Base(PlaceBase::Local(Local::new(1))) && + PlaceRef { + base: _, + projection: + Some(box Projection { + base, + elem: ProjectionElem::Deref, + }), + } => { + if the_place_err.base == &PlaceBase::Local(Local::new(1)) && + base.is_none() && !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( - the_place_err.ty(self.body, self.infcx.tcx).ty + Place::ty_from( + the_place_err.base, + the_place_err.projection, + self.body, + self.infcx.tcx + ) + .ty )); - reason = if self.is_upvar_field_projection(access_place).is_some() { - ", as it is a captured variable in a `Fn` closure".to_string() - } else { - ", as `Fn` closures cannot mutate their captured variables".to_string() - } + reason = + if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() { + ", as it is a captured variable in a `Fn` closure".to_string() + } else { + ", as `Fn` closures cannot mutate their captured variables".to_string() + } } else if { - if let Place::Base(PlaceBase::Local(local)) = *base { - self.body.local_decls[local].is_ref_for_guard() + if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) { + self.body.local_decls[*local].is_ref_for_guard() } else { false } @@ -100,7 +124,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { item_msg = format!("`{}`", access_place_desc.unwrap()); reason = ", as it is immutable for the pattern guard".to_string(); } else { - let source = self.borrowed_content_source(base); + let source = self.borrowed_content_source(PlaceRef { + base: the_place_err.base, + projection: base, + }); let pointer_type = source.describe_for_immutable_place(); opt_source = Some(source); if let Some(desc) = access_place_desc { @@ -119,11 +146,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => - unreachable!(), + PlaceRef { + base: + PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }), + projection: None, + } => unreachable!(), - Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. })) => { - if let Place::Base(PlaceBase::Static(_)) = access_place { + PlaceRef { + base: + PlaceBase::Static(box Static { + kind: StaticKind::Static(def_id), + .. + }), + projection: None, + } => { + if let Place { + base: PlaceBase::Static(_), + projection: None, + } = access_place { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); } else { @@ -133,22 +176,36 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - Place::Projection(box Projection { + PlaceRef { base: _, - elem: ProjectionElem::Index(_), - }) - | Place::Projection(box Projection { + projection: + Some(box Projection { + base: _, + elem: ProjectionElem::Index(_), + }), + } + | PlaceRef { base: _, - elem: ProjectionElem::ConstantIndex { .. }, - }) - | Place::Projection(box Projection { + projection: + Some(box Projection { + base: _, + elem: ProjectionElem::ConstantIndex { .. }, + }), + } + | PlaceRef { base: _, - elem: ProjectionElem::Subslice { .. }, - }) - | Place::Projection(box Projection { + projection: Some(box Projection { + base: _, + elem: ProjectionElem::Subslice { .. }, + }), + } + | PlaceRef { base: _, - elem: ProjectionElem::Downcast(..), - }) => bug!("Unexpected immutable place."), + projection: Some(box Projection { + base: _, + elem: ProjectionElem::Downcast(..), + }), + } => bug!("Unexpected immutable place."), } debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason); @@ -187,7 +244,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { format!( "mutable borrow occurs due to use of `{}` in closure", // always Some() if the message is printed. - self.describe_place(access_place).unwrap_or_default(), + self.describe_place(access_place.as_place_ref()).unwrap_or_default(), ) ); borrow_span @@ -203,21 +260,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // something like `*((*_1).0`. The local that we get will be a reference to the // struct we've got a field access of (it must be a reference since there's a deref // after the field access). - Place::Projection(box Projection { - base: Place::Projection(box Projection { - base: Place::Projection(box Projection { - base, - elem: ProjectionElem::Deref, + PlaceRef { + base, + projection: Some(box Projection { + base: Some(box Projection { + base: Some(box Projection { + base: base_proj, + elem: ProjectionElem::Deref, + }), + elem: ProjectionElem::Field(field, _), }), - elem: ProjectionElem::Field(field, _), + elem: ProjectionElem::Deref, }), - elem: ProjectionElem::Deref, - }) => { + } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - base.ty(self.body, self.infcx.tcx).ty, + Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -230,43 +290,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }, // Suggest removing a `&mut` from the use of a mutable reference. - Place::Base(PlaceBase::Local(local)) - if { - self.body.local_decls.get(*local).map(|local_decl| { - if let ClearCrossCrate::Set( - mir::BindingForm::ImplicitSelf(kind) - ) = local_decl.is_user_variable.as_ref().unwrap() { - // Check if the user variable is a `&mut self` and we can therefore - // suggest removing the `&mut`. - // - // Deliberately fall into this case for all implicit self types, - // so that we don't fall in to the next case with them. - *kind == mir::ImplicitSelfKind::MutRef - } else if Some(kw::SelfLower) == local_decl.name { - // Otherwise, check if the name is the self kewyord - in which case - // we have an explicit self. Do the same thing in this case and check - // for a `self: &mut Self` to suggest removing the `&mut`. - if let ty::Ref( - _, _, hir::Mutability::MutMutable - ) = local_decl.ty.sty { - true - } else { - false - } + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } if { + self.body.local_decls.get(*local).map(|local_decl| { + if let ClearCrossCrate::Set( + mir::BindingForm::ImplicitSelf(kind) + ) = local_decl.is_user_variable.as_ref().unwrap() { + // Check if the user variable is a `&mut self` and we can therefore + // suggest removing the `&mut`. + // + // Deliberately fall into this case for all implicit self types, + // so that we don't fall in to the next case with them. + *kind == mir::ImplicitSelfKind::MutRef + } else if Some(kw::SelfLower) == local_decl.name { + // Otherwise, check if the name is the self kewyord - in which case + // we have an explicit self. Do the same thing in this case and check + // for a `self: &mut Self` to suggest removing the `&mut`. + if let ty::Ref( + _, _, hir::Mutability::MutMutable + ) = local_decl.ty.sty { + true } else { false } - }).unwrap_or(false) - } => - { + } else { + false + } + }).unwrap_or(false) + } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_label(span, "try removing `&mut` here"); }, // We want to suggest users use `let mut` for local (user // variable) mutations... - Place::Base(PlaceBase::Local(local)) - if self.body.local_decls[*local].can_be_made_mutable() => { + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } if self.body.local_decls[*local].can_be_made_mutable() => { // ... but it doesn't make sense to suggest it on // variables that are `ref x`, `ref mut x`, `&self`, // or `&mut self` (such variables are simply not @@ -284,12 +347,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } // Also suggest adding mut for upvars - Place::Projection(box Projection { + PlaceRef { base, - elem: ProjectionElem::Field(upvar_index, _), - }) => { + projection: Some(box Projection { + base: proj_base, + elem: ProjectionElem::Field(upvar_index, _), + }), + } => { debug_assert!(is_closure_or_generator( - base.ty(self.body, self.infcx.tcx).ty + Place::ty_from(&base, &proj_base, self.body, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -317,8 +383,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // complete hack to approximate old AST-borrowck // diagnostic: if the span starts with a mutable borrow of // a local variable, then just suggest the user remove it. - Place::Base(PlaceBase::Local(_)) - if { + PlaceRef { + base: PlaceBase::Local(_), + projection: None, + } if { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { snippet.starts_with("&mut ") } else { @@ -330,10 +398,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label(span, "try removing `&mut` here"); } - Place::Projection(box Projection { - base: Place::Base(PlaceBase::Local(local)), - elem: ProjectionElem::Deref, - }) if { + PlaceRef { + base: PlaceBase::Local(local), + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }), + } if { if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = self.body.local_decls[*local].is_user_variable { @@ -354,10 +425,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // FIXME: can this case be generalized to work for an // arbitrary base for the projection? - Place::Projection(box Projection { - base: Place::Base(PlaceBase::Local(local)), - elem: ProjectionElem::Deref, - }) if self.body.local_decls[*local].is_user_variable.is_some() => + PlaceRef { + base: PlaceBase::Local(local), + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }), + } if self.body.local_decls[*local].is_user_variable.is_some() => { let local_decl = &self.body.local_decls[*local]; let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { @@ -434,10 +508,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - Place::Projection(box Projection { + PlaceRef { base, - elem: ProjectionElem::Deref, - }) if *base == Place::Base(PlaceBase::Local(Local::new(1))) && + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }), + // FIXME document what is this 1 magic number about + } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -447,10 +525,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } - Place::Projection(box Projection { + PlaceRef { base: _, - elem: ProjectionElem::Deref, - }) => { + projection: Some(box Projection { + base: _, + elem: ProjectionElem::Deref, + }), + } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); match opt_source { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 058cdec5cea69..055568f0a27a2 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -128,7 +128,10 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { // When we see `X = ...`, then kill borrows of // `(*X).foo` and so forth. if let Some(all_facts) = self.all_facts { - if let Place::Base(PlaceBase::Local(temp)) = place { + if let Place { + base: PlaceBase::Local(temp), + projection: None, + } = place { 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 { 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 ed88b16253584..abb84c59d9b9e 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -7,7 +7,7 @@ use crate::borrow_check::nll::ConstraintDescription; use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use rustc::mir::{ CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase, - Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, + Rvalue, Statement, StatementKind, TerminatorKind, }; use rustc::ty::{self, TyCtxt}; use rustc::ty::adjustment::{PointerCast}; @@ -252,7 +252,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(Cause::LiveVar(local, location)) => { let span = body.source_info(location).span; let spans = self - .move_spans(&Place::from(local), location) + .move_spans(Place::from(local).as_place_ref(), location) .or_else(|| self.borrow_spans(span, location)); let borrow_location = location; @@ -272,7 +272,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut should_note_order = false; if body.local_decls[local].name.is_some() { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { - if let Place::Base(PlaceBase::Local(borrowed_local)) = place { + if let Place { + base: PlaceBase::Local(borrowed_local), + projection: None, + } = place { if body.local_decls[*borrowed_local].name.is_some() && local != *borrowed_local { @@ -301,7 +304,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { region, ); if let Some(region_name) = region_name { - let opt_place_desc = self.describe_place(&borrow.borrowed_place); + let opt_place_desc = + self.describe_place(borrow.borrowed_place.as_place_ref()); BorrowExplanation::MustBeValidFor { category, from_closure, @@ -489,8 +493,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { Operand::Constant(c) => c.span, - Operand::Copy(Place::Base(PlaceBase::Local(l))) | - Operand::Move(Place::Base(PlaceBase::Local(l))) => { + Operand::Copy(Place { + base: PlaceBase::Local(l), + projection: None, + }) | + Operand::Move(Place { + base: PlaceBase::Local(l), + projection: None, + }) => { let local_decl = &self.body.local_decls[*l]; if local_decl.name.is_none() { local_decl.source_info.span @@ -531,7 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // it which simplifies the termination logic. let mut queue = vec![location]; let mut target = if let Some(&Statement { - kind: StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _), + kind: StatementKind::Assign(Place { + base: PlaceBase::Local(local), + projection: None, + }, _), .. }) = stmt { @@ -555,13 +568,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // The only kind of statement that we care about is assignments... if let StatementKind::Assign(place, box rvalue) = &stmt.kind { - let into = match place { - Place::Base(PlaceBase::Local(into)) => into, - Place::Projection(box Projection { - base: Place::Base(PlaceBase::Local(into)), - elem: ProjectionElem::Deref, - }) => into, - _ => { + let into = match place.local_or_deref_local() { + Some(into) => into, + None => { // Continue at the next location. queue.push(current_location.successor_within_block()); continue; @@ -572,11 +581,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If we see a use, we should check whether it is our data, and if so // update the place that we're looking for to that new place. Rvalue::Use(operand) => match operand { - Operand::Copy(Place::Base(PlaceBase::Local(from))) - | Operand::Move(Place::Base(PlaceBase::Local(from))) + Operand::Copy(Place { + base: PlaceBase::Local(from), + projection: None, + }) + | Operand::Move(Place { + base: PlaceBase::Local(from), + projection: None, + }) if *from == target => { - target = *into; + target = into; } _ => {} }, @@ -585,8 +600,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Cast( CastKind::Pointer(PointerCast::Unsize), operand, ty ) => match operand { - Operand::Copy(Place::Base(PlaceBase::Local(from))) - | Operand::Move(Place::Base(PlaceBase::Local(from))) + Operand::Copy(Place { + base: PlaceBase::Local(from), + projection: None, + }) + | Operand::Move(Place { + base: PlaceBase::Local(from), + projection: None, + }) if *from == target => { debug!("was_captured_by_trait_object: ty={:?}", ty); @@ -616,7 +637,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("was_captured_by_trait_object: terminator={:?}", terminator); if let TerminatorKind::Call { - destination: Some((Place::Base(PlaceBase::Local(dest)), block)), + destination: Some((Place { + base: PlaceBase::Local(dest), + projection: None, + }, block)), args, .. } = &terminator.kind @@ -627,7 +651,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); // Check if one of the arguments to this function is the target place. let found_target = args.iter().any(|arg| { - if let Operand::Move(Place::Base(PlaceBase::Local(potential))) = arg { + if let Operand::Move(Place { + base: PlaceBase::Local(potential), + projection: None, + }) = arg { *potential == target } else { false 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 dbb5a52e0aaa8..b0e364fa2dd9a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -499,13 +499,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }; // FIXME use place_projection.is_empty() when is available - if let Place::Base(_) = place { + if place.projection.is_none() { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { let is_promoted = match place { - Place::Base(PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), - .. - })) => true, + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }), + projection: None, + } => true, _ => false, }; @@ -1345,15 +1348,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // of lowering. Assignments to other sorts of places *are* interesting // though. let category = match *place { - Place::Base(PlaceBase::Local(RETURN_PLACE)) => if let BorrowCheckContext { + Place { + base: PlaceBase::Local(RETURN_PLACE), + projection: None, + } => if let BorrowCheckContext { universal_regions: UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, .. - } = self.borrowck_context - { + } = self.borrowck_context { if tcx.is_static(*def_id) { ConstraintCategory::UseAsStatic } else { @@ -1362,8 +1367,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } else { ConstraintCategory::Return }, - Place::Base(PlaceBase::Local(l)) - if !body.local_decls[l].is_user_variable.is_some() => { + Place { + base: PlaceBase::Local(l), + projection: None, + } if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -1647,7 +1654,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some((ref dest, _target_block)) => { let dest_ty = dest.ty(body, tcx).ty; let category = match *dest { - Place::Base(PlaceBase::Local(RETURN_PLACE)) => { + Place { + base: PlaceBase::Local(RETURN_PLACE), + projection: None, + } => { if let BorrowCheckContext { universal_regions: UniversalRegions { @@ -1666,8 +1676,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Return } } - Place::Base(PlaceBase::Local(l)) - if !body.local_decls[l].is_user_variable.is_some() => { + Place { + base: PlaceBase::Local(l), + projection: None, + } if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } _ => ConstraintCategory::Assignment, @@ -2400,19 +2412,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // *p`, where the `p` has type `&'b mut Foo`, for example, we // need to ensure that `'b: 'a`. - let mut borrowed_place = borrowed_place; + let mut borrowed_projection = &borrowed_place.projection; debug!( "add_reborrow_constraint({:?}, {:?}, {:?})", location, borrow_region, borrowed_place ); - while let Place::Projection(box Projection { base, elem }) = borrowed_place { - debug!("add_reborrow_constraint - iteration {:?}", borrowed_place); + while let Some(box proj) = borrowed_projection { + debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection); - match *elem { + match proj.elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = base.ty(body, tcx).ty; + let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { @@ -2477,7 +2489,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // The "propagate" case. We need to check that our base is valid // for the borrow's lifetime. - borrowed_place = base; + borrowed_projection = &proj.base; } } diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 538ac6881d90a..75065816df050 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -50,7 +50,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( body, &borrowed.borrowed_place, borrowed.kind, - place, + place.as_place_ref(), access, places_conflict::PlaceConflictBias::Overlap, ) { diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index a8f28b64b4953..72d5588c34120 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -55,7 +55,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { for proj in place_projection { if proj.elem == ProjectionElem::Deref { - let ty = proj.base.ty(body, tcx).ty; + let ty = Place::ty_from(place_base, &proj.base, body, tcx).ty; match ty.sty { // For both derefs of raw pointers and `&T` // references, the original path is `Copy` and diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 64ca00defc9c0..348214f97f256 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -3,8 +3,8 @@ use crate::borrow_check::Overlap; use crate::borrow_check::{Deep, Shallow, AccessDepth}; use rustc::hir; use rustc::mir::{ - BorrowKind, Body, Place, PlaceBase, Projection, ProjectionElem, ProjectionsIter, - StaticKind + Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter, + StaticKind, }; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -36,7 +36,7 @@ crate fn places_conflict<'tcx>( body, borrow_place, BorrowKind::Mut { allow_two_phase_borrow: true }, - access_place, + access_place.as_place_ref(), AccessDepth::Deep, bias, ) @@ -51,7 +51,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( body: &Body<'tcx>, borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, - access_place: &Place<'tcx>, + access_place: PlaceRef<'_, 'tcx>, access: AccessDepth, bias: PlaceConflictBias, ) -> bool { @@ -62,8 +62,14 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( // 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::Base(PlaceBase::Local(l1)) = borrow_place { - if let Place::Base(PlaceBase::Local(l2)) = access_place { + if let Place { + base: PlaceBase::Local(l1), + projection: None, + } = borrow_place { + if let PlaceRef { + base: PlaceBase::Local(l2), + projection: None, + } = access_place { return l1 == l2; } } @@ -175,7 +181,7 @@ fn place_components_conflict<'tcx>( // check whether the components being borrowed vs // accessed are disjoint (as in the second example, // but not the first). - match place_projection_conflict(tcx, body, borrow_c, access_c, bias) { + match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) { Overlap::Arbitrary => { // We have encountered different fields of potentially // the same union - the borrow now partially overlaps. @@ -214,7 +220,7 @@ fn place_components_conflict<'tcx>( let base = &borrow_c.base; let elem = &borrow_c.elem; - let base_ty = base.ty(body, tcx).ty; + let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty; match (elem, &base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) @@ -368,6 +374,7 @@ fn place_base_conflict<'tcx>( fn place_projection_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, + pi1_base: &PlaceBase<'tcx>, pi1: &Projection<'tcx>, pi2: &Projection<'tcx>, bias: PlaceConflictBias, @@ -384,7 +391,7 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = pi1.base.ty(body, tcx).ty; + let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty; match ty.sty { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 0cc1dfd4def0f..ecafd4eb1157e 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -11,26 +11,23 @@ use super::MirBorrowckCtxt; use rustc::hir; use rustc::ty::{self, TyCtxt}; -use rustc::mir::{Body, Place, PlaceBase, ProjectionElem}; +use rustc::mir::{Body, Place, PlaceBase, PlaceRef, ProjectionElem}; -pub trait IsPrefixOf<'tcx> { - fn is_prefix_of(&self, other: &Place<'tcx>) -> bool; +pub trait IsPrefixOf<'cx, 'tcx> { + fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool; } -impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> { - fn is_prefix_of(&self, other: &Place<'tcx>) -> bool { - let mut cursor = other; +impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> { + fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool { + let mut cursor = other.projection; loop { - if self == cursor { - return true; + if self.projection == cursor { + return self.base == other.base; } - match *cursor { - Place::Base(PlaceBase::Local(_)) | - Place::Base(PlaceBase::Static(_)) => return false, - Place::Projection(ref proj) => { - cursor = &proj.base; - } + match cursor { + None => return false, + Some(proj) => cursor = &proj.base, } } } @@ -40,7 +37,7 @@ pub(super) struct Prefixes<'cx, 'tcx> { body: &'cx Body<'tcx>, tcx: TyCtxt<'tcx>, kind: PrefixSet, - next: Option<&'cx Place<'tcx>>, + next: Option<(PlaceRef<'cx, 'tcx>)>, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -59,9 +56,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Returns an iterator over the prefixes of `place` /// (inclusive) from longest to smallest, potentially /// terminating the iteration early based on `kind`. - pub(super) fn prefixes(&self, place: &'cx Place<'tcx>, kind: PrefixSet) -> Prefixes<'cx, 'tcx> { + pub(super) fn prefixes( + &self, + place_ref: PlaceRef<'cx, 'tcx>, + kind: PrefixSet, + ) -> Prefixes<'cx, 'tcx> { Prefixes { - next: Some(place), + next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx, @@ -70,7 +71,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { - type Item = &'cx Place<'tcx>; + type Item = PlaceRef<'cx, 'tcx>; fn next(&mut self) -> Option { let mut cursor = self.next?; @@ -80,27 +81,42 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // downcasts here, but may return a base of a downcast). 'cursor: loop { - let proj = match *cursor { - Place::Base(PlaceBase::Local(_)) | // search yielded this leaf - Place::Base(PlaceBase::Static(_)) => { + let proj = match &cursor { + PlaceRef { + base: PlaceBase::Local(_), + projection: None, + } + | // search yielded this leaf + PlaceRef { + base: PlaceBase::Static(_), + projection: None, + } => { self.next = None; return Some(cursor); } - - Place::Projection(ref proj) => proj, + PlaceRef { + base: _, + projection: Some(proj), + } => proj, }; match proj.elem { ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { - // FIXME: add union handling - self.next = Some(&proj.base); + // FIXME: add union handling + self.next = Some(PlaceRef { + base: cursor.base, + projection: &proj.base, + }); return Some(cursor); } ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { - cursor = &proj.base; + cursor = PlaceRef { + base: cursor.base, + projection: &proj.base, + }; continue 'cursor; } ProjectionElem::Deref => { @@ -121,7 +137,10 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { PrefixSet::All => { // all prefixes: just blindly enqueue the base // of the projection - self.next = Some(&proj.base); + self.next = Some(PlaceRef { + base: cursor.base, + projection: &proj.base, + }); return Some(cursor); } PrefixSet::Supporting => { @@ -134,7 +153,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = proj.base.ty(self.body, self.tcx).ty; + let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty; match ty.sty { ty::RawPtr(_) | ty::Ref( @@ -152,12 +171,18 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { _, /*ty*/ hir::MutMutable, ) => { - self.next = Some(&proj.base); + self.next = Some(PlaceRef { + base: cursor.base, + projection: &proj.base, + }); return Some(cursor); } ty::Adt(..) if ty.is_box() => { - self.next = Some(&proj.base); + self.next = Some(PlaceRef { + base: cursor.base, + projection: &proj.base, + }); return Some(cursor); } diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 9c5569011df4f..2587d14a73a8f 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -59,7 +59,7 @@ impl GatherUsedMutsVisitor<'_, '_, '_> { // 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() { + if let PlaceBase::Local(local) = into.base { let _ = self.never_initialized_mut_locals.remove(&local); } } @@ -90,7 +90,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc ) { match &statement.kind { StatementKind::Assign(into, _) => { - if let Some(local) = into.base_local() { + if let PlaceBase::Local(local) = into.base { debug!( "visit_statement: statement={:?} local={:?} \ never_initialized_mut_locals={:?}", @@ -118,7 +118,10 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc "assignment of {:?} to {:?}, adding {:?} to used mutable set", path.place, local, path.place ); - if let Place::Base(PlaceBase::Local(user_local)) = path.place { + if let Place { + base: PlaceBase::Local(user_local), + projection: None, + } = path.place { self.mbcx.used_mut.insert(user_local); } } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 82accb47437c6..2d9e7ac75c7b8 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -123,10 +123,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; block.and(place) } - ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static { - ty: expr.ty, - kind: StaticKind::Static(id), - })))), + ExprKind::StaticRef { id } => block.and(Place { + base: PlaceBase::Static(Box::new(Static { + ty: expr.ty, + kind: StaticKind::Static(id), + })), + projection: None, + }), ExprKind::PlaceTypeAscription { source, user_ty } => { let place = unpack!(block = this.as_place(block, source)); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 56c518a6d57a8..851a6b0b07cf6 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -497,32 +497,48 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arg_place = unpack!(block = this.as_place(block, arg)); let mutability = match arg_place { - Place::Base(PlaceBase::Local(local)) => this.local_decls[local].mutability, - Place::Projection(box Projection { - base: Place::Base(PlaceBase::Local(local)), - elem: ProjectionElem::Deref, - }) => { + Place { + base: PlaceBase::Local(local), + projection: None, + } => this.local_decls[local].mutability, + Place { + base: PlaceBase::Local(local), + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }) + } => { debug_assert!( this.local_decls[local].is_ref_for_guard(), "Unexpected capture place", ); this.local_decls[local].mutability } - Place::Projection(box Projection { + Place { + ref base, + projection: Some(box Projection { + base: ref base_proj, + elem: ProjectionElem::Field(upvar_index, _), + }), + } + | Place { ref base, - elem: ProjectionElem::Field(upvar_index, _), - }) - | Place::Projection(box Projection { - base: - Place::Projection(box Projection { - ref base, + projection: Some(box Projection { + base: Some(box Projection { + base: ref base_proj, elem: ProjectionElem::Field(upvar_index, _), }), - elem: ProjectionElem::Deref, - }) => { + elem: ProjectionElem::Deref, + }), + } => { + let place = PlaceRef { + base, + projection: base_proj, + }; + // Not projected from the implicit `self` in a closure. debug_assert!( - match base.local_or_deref_local() { + match place.local_or_deref_local() { Some(local) => local == Local::new(1), None => false, }, diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index e433da904a678..2815361a64760 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -296,7 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Create a "fake" temporary variable so that we check that the // value is Sized. Usually, this is caught in type checking, but // in the case of box expr there is no such check. - if let Place::Projection(..) = destination { + if destination.projection.is_some() { this.local_decls .push(LocalDecl::new_temp(expr.ty, expr.span)); } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index dafb8c5f8f706..b58cef9cce1e7 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -536,7 +536,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let var_ty = self.local_decls[local_id].ty; let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); self.schedule_drop(span, region_scope, local_id, var_ty, DropKind::Storage); - Place::Base(PlaceBase::Local(local_id)) + Place::from(local_id) } pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) { @@ -937,11 +937,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for Binding { source, .. } in matched_candidates.iter().flat_map(|candidate| &candidate.bindings) { - let mut cursor = source; - while let Place::Projection(box Projection { base, elem }) = cursor { + let mut cursor = &source.projection; + while let Some(box Projection { base, elem }) = cursor { cursor = base; if let ProjectionElem::Deref = elem { - fake_borrows.insert(cursor.clone()); + fake_borrows.insert(Place { + base: source.base.clone(), + projection: cursor.clone(), + }); break; } } @@ -1277,7 +1280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, fake_borrows: &'b FxHashSet>, temp_span: Span, - ) -> Vec<(&'b Place<'tcx>, Local)> { + ) -> Vec<(PlaceRef<'b, 'tcx>, Local)> { let tcx = self.hir.tcx(); debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows); @@ -1287,18 +1290,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of the prefixes of any fake borrows. for place in fake_borrows { - let mut prefix_cursor = place; - while let Place::Projection(box Projection { base, elem }) = prefix_cursor { + let mut prefix_cursor = &place.projection; + while let Some(box Projection { base, elem }) = prefix_cursor { if let ProjectionElem::Deref = elem { // Insert a shallow borrow after a deref. For other // projections the borrow of prefix_cursor will // conflict with any mutation of base. - all_fake_borrows.push(base); + all_fake_borrows.push(PlaceRef { + base: &place.base, + projection: base, + }); } prefix_cursor = base; } - all_fake_borrows.push(place); + all_fake_borrows.push(place.as_place_ref()); } // Deduplicate and ensure a deterministic order. @@ -1308,7 +1314,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); all_fake_borrows.into_iter().map(|matched_place| { - let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; + let fake_borrow_deref_ty = Place::ty_from( + matched_place.base, + matched_place.projection, + &self.local_decls, + tcx, + ) + .ty; let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); let fake_borrow_temp = self.local_decls.push( LocalDecl::new_temp(fake_borrow_ty, temp_span) @@ -1339,7 +1351,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: Candidate<'pat, 'tcx>, guard: Option>, - fake_borrows: &Vec<(&Place<'tcx>, Local)>, + fake_borrows: &Vec<(PlaceRef<'_, 'tcx>, Local)>, scrutinee_span: Span, region_scope: region::Scope, ) -> BasicBlock { @@ -1470,16 +1482,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let re_erased = tcx.lifetimes.re_erased; let scrutinee_source_info = self.source_info(scrutinee_span); - for &(place, temp) in fake_borrows { + for (place, temp) in fake_borrows { let borrow = Rvalue::Ref( re_erased, BorrowKind::Shallow, - place.clone(), + Place { + base: place.base.clone(), + projection: place.projection.clone(), + }, ); self.cfg.push_assign( block, scrutinee_source_info, - &Place::from(temp), + &Place::from(*temp), borrow, ); } @@ -1549,7 +1564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { let local_id = self.var_local_id(binding.var_id, RefWithinGuard); - let place = Place::from(local_id); + let place = Place::from(local_id); self.cfg.push( post_guard_block, Statement { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a74d5d7ab2de3..a04c041ca9dc7 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -851,8 +851,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If constants and statics, we don't generate StorageLive for this // temporary, so don't try to generate StorageDead for it either. _ if self.local_scope().is_none() => (), - Operand::Copy(Place::Base(PlaceBase::Local(cond_temp))) - | Operand::Move(Place::Base(PlaceBase::Local(cond_temp))) => { + Operand::Copy(Place { + base: PlaceBase::Local(cond_temp), + projection: None, + }) + | Operand::Move(Place { + base: PlaceBase::Local(cond_temp), + projection: None, + }) => { // Manually drop the condition on both branches. let top_scope = self.scopes.scopes.last_mut().unwrap(); let top_drop_data = top_scope.drops.pop().unwrap(); diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index a73ec2ed8e06a..b6dd544d39561 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -14,8 +14,8 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, { let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { - match move_data.move_paths[child_index].place { - mir::Place::Projection(ref proj) => { + match move_data.move_paths[child_index].place.projection { + Some(ref proj) => { if cond(proj) { return Some(child_index) } @@ -171,7 +171,7 @@ pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>( let move_data = &ctxt.move_data; for arg in body.args_iter() { let place = mir::Place::from(arg); - let lookup_result = move_data.rev_lookup.find(&place); + let lookup_result = move_data.rev_lookup.find(place.as_place_ref()); on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| callback(mpi, DropFlagState::Present)); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index dcc6ba5ca05cc..10c3e52b5255a 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { ) { debug!("kill_borrows_on_place: place={:?}", place); - if let Some(local) = place.base_local() { + if let PlaceBase::Local(local) = place.base { let other_borrows_of_local = self .borrow_set .local_map @@ -205,7 +205,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // If the borrowed place is a local with no projections, all other borrows of this // local must conflict. This is purely an optimization so we don't have to call // `places_conflict` for every borrow. - if let Place::Base(PlaceBase::Local(_)) = place { + if place.projection.is_none() { trans.kill_all(other_borrows_of_local); return; } diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 065cfe8a4e823..ade732bbb7597 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -309,7 +309,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { // when a call returns successfully, that means we need to set // the bits for that dest_place to 1 (initialized). on_lookup_result_bits(self.tcx, self.body, self.move_data(), - self.move_data().rev_lookup.find(dest_place), + self.move_data().rev_lookup.find(dest_place.as_place_ref()), |mpi| { in_out.insert(mpi); }); } } @@ -367,7 +367,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> { // when a call returns successfully, that means we need to set // the bits for that dest_place to 0 (initialized). on_lookup_result_bits(self.tcx, self.body, self.move_data(), - self.move_data().rev_lookup.find(dest_place), + self.move_data().rev_lookup.find(dest_place.as_place_ref()), |mpi| { in_out.remove(mpi); }); } } @@ -423,7 +423,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { // when a call returns successfully, that means we need to set // the bits for that dest_place to 1 (initialized). on_lookup_result_bits(self.tcx, self.body, self.move_data(), - self.move_data().rev_lookup.find(dest_place), + self.move_data().rev_lookup.find(dest_place.as_place_ref()), |mpi| { in_out.insert(mpi); }); } } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 7fa950cb98d34..0e01701ea9e44 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -121,11 +121,15 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { StatementKind::StorageDead(l) => sets.kill(l), StatementKind::Assign(ref place, _) | StatementKind::SetDiscriminant { ref place, .. } => { - place.base_local().map(|l| sets.gen(l)); + if let PlaceBase::Local(local) = place.base { + sets.gen(local); + } } StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => { for p in &**outputs { - p.base_local().map(|l| sets.gen(l)); + if let PlaceBase::Local(local) = p.base { + sets.gen(local); + } } } _ => (), @@ -146,7 +150,9 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { _dest_bb: mir::BasicBlock, dest_place: &mir::Place<'tcx>, ) { - dest_place.base_local().map(|l| in_out.insert(l)); + if let PlaceBase::Local(local) = dest_place.base { + in_out.insert(local); + } } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index f05dfad32572d..3bdd3e3da048e 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -314,12 +314,12 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> { fn visit_statement_entry(&mut self, _loc: Location, - _stmt: &Statement<'tcx>, + _stmt: &'a Statement<'tcx>, _flow_state: &Self::FlowState) {} fn visit_terminator_entry(&mut self, _loc: Location, - _term: &Terminator<'tcx>, + _term: &'a Terminator<'tcx>, _flow_state: &Self::FlowState) {} // Main entry point: this drives the processing of results. diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index f282c276e0926..436ac30ffb42e 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -106,13 +106,16 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { for proj in place_projection { let body = self.builder.body; let tcx = self.builder.tcx; - let place_ty = proj.base.ty(body, tcx).ty; + let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty; match place_ty.sty { ty::Ref(..) | ty::RawPtr(..) => return Err(MoveError::cannot_move_out_of( self.loc, BorrowedContent { - target_place: Place::Projection(Box::new(proj.clone())), + target_place: Place { + base: place_base.clone(), + projection: Some(Box::new(proj.clone())), + } })), ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => return Err(MoveError::cannot_move_out_of(self.loc, @@ -159,7 +162,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { &mut self.builder.data.path_map, &mut self.builder.data.init_path_map, Some(base), - Place::Projection(Box::new(proj.clone())), + Place { + base: place_base.clone(), + projection: Some(Box::new(proj.clone())), + }, ); ent.insert(path); path @@ -268,9 +274,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // 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.as_place_ref(), InitKind::Shallow); } else { - self.gather_init(place, InitKind::Deep); + self.gather_init(place.as_place_ref(), InitKind::Deep); } self.gather_rvalue(rval); } @@ -280,7 +286,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { StatementKind::InlineAsm(ref asm) => { for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect { - self.gather_init(output, InitKind::Deep); + self.gather_init(output.as_place_ref(), InitKind::Deep); } } for (_, input) in asm.inputs.iter() { @@ -370,7 +376,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { TerminatorKind::DropAndReplace { ref location, ref value, .. } => { self.create_move_path(location); self.gather_operand(value); - self.gather_init(location, InitKind::Deep); + self.gather_init(location.as_place_ref(), InitKind::Deep); } TerminatorKind::Call { ref func, @@ -385,7 +391,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } if let Some((ref destination, _bb)) = *destination { self.create_move_path(destination); - self.gather_init(destination, InitKind::NonPanicPathOnly); + self.gather_init(destination.as_place_ref(), InitKind::NonPanicPathOnly); } } } @@ -420,22 +426,24 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.builder.data.loc_map[self.loc].push(move_out); } - fn gather_init(&mut self, place: &Place<'tcx>, kind: InitKind) { + fn gather_init(&mut self, place: PlaceRef<'cx, 'tcx>, kind: InitKind) { debug!("gather_init({:?}, {:?})", self.loc, place); - let place = match place { - // Check if we are assigning into a field of a union, if so, lookup the place - // of the union so it is marked as initialized again. - Place::Projection(box Projection { - base, - elem: ProjectionElem::Field(_, _), - }) if match base.ty(self.builder.body, self.builder.tcx).ty.sty { - ty::Adt(def, _) if def.is_union() => true, - _ => false, - } => base, - // Otherwise, lookup the place. - _ => place, - }; + let mut place = place; + + // Check if we are assigning into a field of a union, if so, lookup the place + // of the union so it is marked as initialized again. + if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) = + place.projection + { + if let ty::Adt(def, _) = + Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty + { + if def.is_union() { + place = PlaceRef { base: place.base, projection: proj_base } + } + } + } if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) { let init = self.builder.data.inits.push(Init { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 938450c63aefc..5c2255882b2c7 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -240,8 +240,8 @@ impl MovePathLookup { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place: &Place<'tcx>) -> LookupResult { - place.iterate(|place_base, place_projection| { + pub fn find(&self, place_ref: PlaceRef<'cx, 'tcx>) -> LookupResult { + place_ref.iterate(|place_base, place_projection| { let mut result = match place_base { PlaceBase::Local(local) => self.locals[*local], PlaceBase::Static(..) => return LookupResult::Parent(None), @@ -318,7 +318,10 @@ impl<'tcx> MoveData<'tcx> { pub fn base_local(&self, mut mpi: MovePathIndex) -> Option { loop { let path = &self.move_paths[mpi]; - if let Place::Base(PlaceBase::Local(l)) = path.place { return Some(l); } + if let Place { + base: PlaceBase::Local(l), + projection: None, + } = path.place { return Some(l); } if let Some(parent) = path.parent { mpi = parent; continue } else { return None } } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 3d97132e53969..1816171d7b127 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -455,17 +455,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { mir_place: &mir::Place<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - use rustc::mir::Place; use rustc::mir::PlaceBase; mir_place.iterate(|place_base, place_projection| { let mut op = match place_base { PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer), PlaceBase::Local(local) => { - // FIXME use place_projection.is_empty() when is available // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. - let layout = if let Place::Base(_) = mir_place { + // FIXME use place_projection.is_empty() when is available + let layout = if mir_place.projection.is_none() { layout } else { None diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index de5af0a46b534..887f93c647878 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -15,34 +15,30 @@ pub struct AddRetag; /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic /// copies. Data races are UB.) fn is_stable( - place: &Place<'_>, + place: PlaceRef<'_, '_>, ) -> bool { - use rustc::mir::Place::*; - - match *place { - // Locals and statics have stable addresses, for sure - Base(PlaceBase::Local { .. }) | - Base(PlaceBase::Static { .. }) => - true, - // Recurse for projections - Projection(ref proj) => { - match proj.elem { - // Which place this evaluates to can change with any memory write, - // so cannot assume this to be stable. - ProjectionElem::Deref => - false, - // Array indices are intersting, but MIR building generates a *fresh* - // temporary for every array access, so the index cannot be changed as - // a side-effect. - ProjectionElem::Index { .. } | - // The rest is completely boring, they just offset by a constant. - ProjectionElem::Field { .. } | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Subslice { .. } | - ProjectionElem::Downcast { .. } => - is_stable(&proj.base), - } + if let Some(proj) = &place.projection { + match proj.elem { + // Which place this evaluates to can change with any memory write, + // so cannot assume this to be stable. + ProjectionElem::Deref => + false, + // Array indices are intersting, but MIR building generates a *fresh* + // temporary for every array access, so the index cannot be changed as + // a side-effect. + ProjectionElem::Index { .. } | + // The rest is completely boring, they just offset by a constant. + ProjectionElem::Field { .. } | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Subslice { .. } | + ProjectionElem::Downcast { .. } => + is_stable(PlaceRef { + base: place.base, + projection: &proj.base, + }), } + } else { + true } } @@ -83,7 +79,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).ty, tcx) + is_stable(place.as_place_ref()) + && may_have_reference(place.ty(&*local_decls, tcx).ty, tcx) }; // PART 1 diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0c48531e34521..d5c5267a119d3 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -248,8 +248,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { }], &[]); } } - let is_borrow_of_interior_mut = context.is_borrow() && !proj.base - .ty(self.body, self.tcx) + let is_borrow_of_interior_mut = context.is_borrow() && + !Place::ty_from(&place.base, &proj.base, self.body, self.tcx) .ty .is_freeze(self.tcx, self.param_env, self.source_info.span); // prevent @@ -264,15 +264,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); } let old_source_info = self.source_info; - if let Place::Base(PlaceBase::Local(local)) = proj.base { - if self.body.local_decls[local].internal { + if let (PlaceBase::Local(local), None) = (&place.base, &proj.base) { + if self.body.local_decls[*local].internal { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. - self.source_info = self.body.local_decls[local].source_info; + self.source_info = self.body.local_decls[*local].source_info; } } - let base_ty = proj.base.ty(self.body, self.tcx).ty; + let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty; match base_ty.sty { ty::RawPtr(..) => { self.require_unsafe("dereference of raw pointer", @@ -404,15 +404,16 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } fn check_mut_borrowing_layout_constrained_field( &mut self, - mut place: &Place<'tcx>, + place: &Place<'tcx>, is_mut_use: bool, ) { - while let &Place::Projection(box Projection { - ref base, ref elem - }) = place { - match *elem { + let mut projection = &place.projection; + while let Some(proj) = projection { + match proj.elem { ProjectionElem::Field(..) => { - let ty = base.ty(&self.body.local_decls, self.tcx).ty; + let ty = + Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx) + .ty; match ty.sty { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, @@ -446,7 +447,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } _ => {} } - place = base; + projection = &proj.base; } } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 29480f88fcedc..72390228aa839 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -781,7 +781,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { .ty; 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::Base(PlaceBase::Local(local)) = *place { + if let Place { + base: PlaceBase::Local(local), + projection: None, + } = *place { trace!("checking whether {:?} can be stored to {:?}", value, local); if self.can_const_prop[local] { trace!("storing {:?} to {:?}", value, local); @@ -821,11 +824,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { // doesn't use the invalid value match cond { Operand::Move(ref place) | Operand::Copy(ref place) => { - let mut place = place; - while let Place::Projection(ref proj) = *place { - place = &proj.base; - } - if let Place::Base(PlaceBase::Local(local)) = *place { + if let PlaceBase::Local(local) = place.base { self.remove_const(local); } }, diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 88a46b1012b61..7c9eeb5a57741 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -94,7 +94,10 @@ impl MirPass for CopyPropagation { // That use of the source must be an assignment. match statement.kind { StatementKind::Assign( - Place::Base(PlaceBase::Local(local)), + Place { + base: PlaceBase::Local(local), + projection: None, + }, box Rvalue::Use(ref operand) ) if local == dest_local => { let maybe_action = match *operand { @@ -145,12 +148,24 @@ fn eliminate_self_assignments( if let Some(stmt) = body[location.block].statements.get(location.statement_index) { match stmt.kind { StatementKind::Assign( - Place::Base(PlaceBase::Local(local)), - box Rvalue::Use(Operand::Copy(Place::Base(PlaceBase::Local(src_local)))), + Place { + base: PlaceBase::Local(local), + projection: None, + }, + box Rvalue::Use(Operand::Copy(Place { + base: PlaceBase::Local(src_local), + projection: None, + })), ) | StatementKind::Assign( - Place::Base(PlaceBase::Local(local)), - box Rvalue::Use(Operand::Move(Place::Base(PlaceBase::Local(src_local)))), + Place { + base: PlaceBase::Local(local), + projection: None, + }, + box Rvalue::Use(Operand::Move(Place { + base: PlaceBase::Local(src_local), + projection: None, + })), ) if local == dest_local && dest_local == src_local => {} _ => { continue; @@ -177,7 +192,10 @@ impl<'tcx> Action<'tcx> { fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>) -> Option> { // The source must be a local. - let src_local = if let Place::Base(PlaceBase::Local(local)) = *src_place { + let src_local = if let Place { + base: PlaceBase::Local(local), + projection: None, + } = *src_place { local } else { debug!(" Can't copy-propagate local: source is not a local"); @@ -331,8 +349,14 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { self.super_operand(operand, location); match *operand { - Operand::Copy(Place::Base(PlaceBase::Local(local))) | - Operand::Move(Place::Base(PlaceBase::Local(local))) if local == self.dest_local => {} + Operand::Copy(Place { + base: PlaceBase::Local(local), + projection: None, + }) | + Operand::Move(Place { + base: PlaceBase::Local(local), + projection: None, + }) if local == self.dest_local => {} _ => return, } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index ad19b974d7d61..0748321f60593 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -105,7 +105,7 @@ fn find_dead_unwinds<'tcx>( init_data.apply_location(tcx, body, env, loc); } - let path = match env.move_data.rev_lookup.find(location) { + let path = match env.move_data.rev_lookup.find(location.as_place_ref()) { LookupResult::Exact(e) => e, LookupResult::Parent(..) => { debug!("find_dead_unwinds: has parent; skipping"); @@ -360,7 +360,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { statement_index: data.statements.len() }); - let path = self.move_data().rev_lookup.find(location); + let path = self.move_data().rev_lookup.find(location.as_place_ref()); debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, location, path); @@ -399,7 +399,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match terminator.kind { TerminatorKind::Drop { ref location, target, unwind } => { let init_data = self.initialization_data_at(loc); - match self.move_data().rev_lookup.find(location) { + match self.move_data().rev_lookup.find(location.as_place_ref()) { LookupResult::Exact(path) => { elaborate_drop( &mut Elaborator { @@ -488,7 +488,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { is_cleanup: false, }); - match self.move_data().rev_lookup.find(location) { + match self.move_data().rev_lookup.find(location.as_place_ref()) { LookupResult::Exact(path) => { debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); let init_data = self.initialization_data_at(loc); @@ -558,7 +558,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(!self.patch.is_patched(bb)); let loc = Location { block: tgt, statement_index: 0 }; - let path = self.move_data().rev_lookup.find(place); + let path = self.move_data().rev_lookup.find(place.as_place_ref()); on_lookup_result_bits( self.tcx, self.body, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) @@ -632,7 +632,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(!self.patch.is_patched(bb)); let loc = Location { block: bb, statement_index: data.statements.len() }; - let path = self.move_data().rev_lookup.find(place); + let path = self.move_data().rev_lookup.find(place.as_place_ref()); on_lookup_result_bits( self.tcx, self.body, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 2ed3f7d5c26e2..af412edbdc23f 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -104,11 +104,14 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.base_local() == Some(self_arg()) { - replace_base(place, Place::Projection(Box::new(Projection { - base: Place::Base(PlaceBase::Local(self_arg())), - elem: ProjectionElem::Deref, - }))); + if place.base == PlaceBase::Local(self_arg()) { + replace_base(place, Place { + base: PlaceBase::Local(self_arg()), + projection: Some(Box::new(Projection { + base: None, + elem: ProjectionElem::Deref, + })), + }); } else { self.super_place(place, context, location); } @@ -131,11 +134,14 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.base_local() == Some(self_arg()) { - replace_base(place, Place::Projection(Box::new(Projection { - base: Place::Base(PlaceBase::Local(self_arg())), - elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty), - }))); + if place.base == PlaceBase::Local(self_arg()) { + replace_base(place, Place { + base: PlaceBase::Local(self_arg()), + projection: Some(Box::new(Projection { + base: None, + elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty), + })), + }); } else { self.super_place(place, context, location); } @@ -143,11 +149,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) { - if let Place::Projection(proj) = place { - replace_base(&mut proj.base, new_base); - } else { - *place = new_base; + let mut projection = &mut place.projection; + while let Some(box proj) = projection { + projection = &mut proj.base; } + + place.base = new_base.base; + *projection = new_base.projection; } fn self_arg() -> Local { @@ -203,10 +211,13 @@ impl TransformVisitor<'tcx> { let self_place = Place::from(self_arg()); let base = self_place.downcast_unnamed(variant_index); let field = Projection { - base: base, + base: base.projection, elem: ProjectionElem::Field(Field::new(idx), ty), }; - Place::Projection(Box::new(field)) + Place { + base: base.base, + projection: Some(Box::new(field)), + } } // Create a statement which changes the discriminant @@ -245,7 +256,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if let Some(l) = place.base_local() { + if let PlaceBase::Local(l) = place.base { // Replace an Local in the remap with a generator struct access if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) { replace_base(place, self.make_field(variant_index, idx, ty)); @@ -835,7 +846,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut &Terminator { source_info, kind: TerminatorKind::Drop { - location: Place::Base(PlaceBase::Local(local)), + location: Place { + base: PlaceBase::Local(local), + projection: None, + }, target, unwind } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 04ee14f5f59be..343832fe4a761 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -603,7 +603,10 @@ impl Inliner<'tcx> { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. - if let Operand::Move(Place::Base(PlaceBase::Local(local))) = arg { + if let Operand::Move(Place { + base: PlaceBase::Local(local), + projection: None, + }) = arg { if caller_body.local_kind(local) == LocalKind::Temp { // Reuse the operand if it's a temporary already return local; @@ -671,7 +674,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { _location: Location) { if *local == RETURN_PLACE { match self.destination { - Place::Base(PlaceBase::Local(l)) => { + Place { + base: PlaceBase::Local(l), + projection: None, + } => { *local = l; return; }, @@ -692,13 +698,20 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { _location: Location) { match place { - Place::Base(PlaceBase::Local(RETURN_PLACE)) => { + Place { + base: PlaceBase::Local(RETURN_PLACE), + projection: None, + } => { // Return pointer; update the place itself *place = self.destination.clone(); }, - Place::Base( - PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. }) - ) => { + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted), + .. + }), + projection: None, + } => { if let Some(p) = self.promoted_map.get(*promoted).cloned() { *promoted = p; } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 40563ad4167d5..5542926503693 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -41,10 +41,14 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { if self.optimizations.and_stars.remove(&location) { debug!("replacing `&*`: {:?}", rvalue); let new_place = match *rvalue { - Rvalue::Ref(_, _, Place::Projection(ref mut projection)) => { + Rvalue::Ref(_, _, Place { + ref mut base, + projection: Some(ref mut projection), + }) => Place { // Replace with dummy - mem::replace(&mut projection.base, Place::Base(PlaceBase::Local(Local::new(0)))) - } + base: mem::replace(base, PlaceBase::Local(Local::new(0))), + projection: projection.base.take(), + }, _ => bug!("Detected `&*` but didn't find `&*`!"), }; *rvalue = Rvalue::Use(Operand::Copy(new_place)) @@ -78,9 +82,12 @@ impl OptimizationFinder<'b, 'tcx> { impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { + if let Rvalue::Ref(_, _, Place { + ref base, + projection: Some(ref projection), + }) = *rvalue { if let ProjectionElem::Deref = projection.elem { - if projection.base.ty(self.body, self.tcx).ty.is_region_ptr() { + if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() { self.optimizations.and_stars.insert(location); } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 33eb4106d0735..3090b63a7e993 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -300,9 +300,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let mut promoted_place = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span); - Place::Base( - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(promoted_id), ty }) - ) + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted_id), + ty + }), + projection: None, + } }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); match candidate { @@ -310,17 +314,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let ref mut statement = blocks[loc.block].statements[loc.statement_index]; match statement.kind { StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => { - // Find the underlying local for this (necessarily interior) borrow. - let mut place = place; - while let Place::Projection(ref mut proj) = *place { - assert_ne!(proj.elem, ProjectionElem::Deref); - place = &mut proj.base; - }; - - let ty = place.ty(local_decls, self.tcx).ty; + // Use the underlying local for this (necessarily interior) borrow. + let ty = place.base.ty(local_decls).ty; let span = statement.source_info.span; - Operand::Move(mem::replace(place, promoted_place(ty, span))) + Operand::Move(Place { + base: mem::replace(&mut place.base, promoted_place(ty, span).base), + projection: None, + }) } _ => bug!() } @@ -397,7 +398,10 @@ pub fn promote_candidates<'tcx>( Candidate::Repeat(Location { block, statement_index }) | Candidate::Ref(Location { block, statement_index }) => { match body[block].statements[statement_index].kind { - StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _) => { + StatementKind::Assign(Place { + base: PlaceBase::Local(local), + projection: None, + }, _) => { if temps[local] == TempState::PromotedOut { // Already promoted. continue; @@ -444,7 +448,10 @@ pub fn promote_candidates<'tcx>( for block in body.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { - StatementKind::Assign(Place::Base(PlaceBase::Local(index)), _) | + StatementKind::Assign(Place { + base: PlaceBase::Local(index), + projection: None, + }, _) | StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { !promoted(index) @@ -454,7 +461,10 @@ pub fn promote_candidates<'tcx>( }); let terminator = block.terminator_mut(); match terminator.kind { - TerminatorKind::Drop { location: Place::Base(PlaceBase::Local(index)), target, .. } => { + TerminatorKind::Drop { location: Place { + base: PlaceBase::Local(index), + projection: None, + }, target, .. } => { if promoted(index) { terminator.kind = TerminatorKind::Goto { target, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4308af7c5ad8d..739e2172b03bc 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -182,12 +182,16 @@ trait Qualif { fn in_projection_structurally( cx: &ConstCx<'_, 'tcx>, + base: &PlaceBase<'tcx>, proj: &Projection<'tcx>, ) -> bool { - let base_qualif = Self::in_place(cx, &proj.base); + let base_qualif = Self::in_place(cx, PlaceRef { + base, + projection: &proj.base, + }); let qualif = base_qualif && Self::mask_for_ty( cx, - proj.base.ty(cx.body, cx.tcx) + Place::ty_from(&base, &proj.base, cx.body, cx.tcx) .projection_ty(cx.tcx, &proj.elem) .ty, ); @@ -202,26 +206,44 @@ trait Qualif { } } - fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool { - Self::in_projection_structurally(cx, proj) + fn in_projection( + cx: &ConstCx<'_, 'tcx>, + base: &PlaceBase<'tcx>, + proj: &Projection<'tcx>, + ) -> bool { + Self::in_projection_structurally(cx, base, proj) } - fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool { - match *place { - Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local), - Place::Base(PlaceBase::Static(box Static {kind: StaticKind::Promoted(_), .. })) => - bug!("qualifying already promoted MIR"), - Place::Base(PlaceBase::Static(ref static_)) => { + fn in_place(cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>) -> bool { + match place { + PlaceRef { + base: PlaceBase::Local(local), + projection: None, + } => Self::in_local(cx, *local), + PlaceRef { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }), + projection: None, + } => bug!("qualifying already promoted MIR"), + PlaceRef { + base: PlaceBase::Static(static_), + projection: None, + } => { Self::in_static(cx, static_) }, - Place::Projection(ref proj) => Self::in_projection(cx, proj), + PlaceRef { + base, + projection: Some(proj), + } => Self::in_projection(cx, base, proj), } } fn in_operand(cx: &ConstCx<'_, 'tcx>, operand: &Operand<'tcx>) -> bool { match *operand { Operand::Copy(ref place) | - Operand::Move(ref place) => Self::in_place(cx, place), + Operand::Move(ref place) => Self::in_place(cx, place.as_place_ref()), Operand::Constant(ref constant) => { if let ConstValue::Unevaluated(def_id, _) = constant.literal.val { @@ -250,7 +272,7 @@ trait Qualif { Rvalue::NullaryOp(..) => false, Rvalue::Discriminant(ref place) | - Rvalue::Len(ref place) => Self::in_place(cx, place), + Rvalue::Len(ref place) => Self::in_place(cx, place.as_place_ref()), Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | @@ -264,16 +286,19 @@ trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let Place::Projection(ref proj) = *place { + if let Some(ref proj) = place.projection { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(cx.body, cx.tcx).ty; + let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.sty { - return Self::in_place(cx, &proj.base); + return Self::in_place(cx, PlaceRef { + base: &place.base, + projection: &proj.base, + }); } } } - Self::in_place(cx, place) + Self::in_place(cx, place.as_place_ref()) } Rvalue::Aggregate(_, ref operands) => { @@ -421,7 +446,11 @@ impl Qualif for IsNotPromotable { } } - fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool { + fn in_projection( + cx: &ConstCx<'_, 'tcx>, + base: &PlaceBase<'tcx>, + proj: &Projection<'tcx>, + ) -> bool { match proj.elem { ProjectionElem::Deref | ProjectionElem::Downcast(..) => return true, @@ -432,7 +461,7 @@ impl Qualif for IsNotPromotable { ProjectionElem::Field(..) => { if cx.mode == Mode::NonConstFn { - let base_ty = proj.base.ty(cx.body, cx.tcx).ty; + let base_ty = Place::ty_from(base, &proj.base, cx.body, cx.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { // No promotion of union field accesses. if def.is_union() { @@ -443,7 +472,7 @@ impl Qualif for IsNotPromotable { } } - Self::in_projection_structurally(cx, proj) + Self::in_projection_structurally(cx, base, proj) } fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { @@ -773,20 +802,24 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // We might have a candidate for promotion. let candidate = Candidate::Ref(location); // Start by traversing to the "base", with non-deref projections removed. - let mut place = place; - while let Place::Projection(ref proj) = *place { + let mut place_projection = &place.projection; + while let Some(proj) = place_projection { if proj.elem == ProjectionElem::Deref { break; } - place = &proj.base; + place_projection = &proj.base; } - debug!("qualify_consts: promotion candidate: place={:?}", place); + + debug!( + "qualify_consts: promotion candidate: place={:?} {:?}", + place.base, place_projection + ); // We can only promote interior borrows of promotable temps (non-temps // don't get promoted anyway). // (If we bailed out of the loop due to a `Deref` above, we will definitely // not enter the conditional here.) - if let Place::Base(PlaceBase::Local(local)) = *place { - if self.body.local_kind(local) == LocalKind::Temp { + if let (PlaceBase::Local(local), None) = (&place.base, place_projection) { + if self.body.local_kind(*local) == LocalKind::Temp { debug!("qualify_consts: promotion candidate: local={:?}", local); // The borrowed place doesn't have `HasMutInterior` // (from `in_rvalue`), so we can safely ignore @@ -794,7 +827,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // This allows borrowing fields which don't have // `HasMutInterior`, from a type that does, e.g.: // `let _: &'static _ = &(Cell::new(1), 2).1;` - let mut local_qualifs = self.qualifs_in_local(local); + let mut local_qualifs = self.qualifs_in_local(*local); // Any qualifications, except HasMutInterior (see above), disqualify // from promotion. // This is, in particular, the "implicit promotion" version of @@ -821,34 +854,31 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { _ => {}, } - let mut dest = dest; + let mut dest_projection = &dest.projection; let index = loop { - match dest { + match (&dest.base, dest_projection) { // We treat all locals equal in constants - Place::Base(PlaceBase::Local(index)) => break *index, + (&PlaceBase::Local(index), None) => break index, // projections are transparent for assignments // we qualify the entire destination at once, even if just a field would have // stricter qualification - Place::Projection(proj) => { + (base, Some(proj)) => { // Catch more errors in the destination. `visit_place` also checks various // projection rules like union field access and raw pointer deref - self.visit_place( - dest, - PlaceContext::MutatingUse(MutatingUseContext::Store), - location - ); - dest = &proj.base; + let context = PlaceContext::MutatingUse(MutatingUseContext::Store); + self.visit_place_base(base, context, location); + self.visit_projection(base, proj, context, location); + dest_projection = &proj.base; }, - Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => - bug!("promoteds don't exist yet during promotion"), - Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => { + (&PlaceBase::Static(box Static { + kind: StaticKind::Promoted(_), + .. + }), None) => bug!("promoteds don't exist yet during promotion"), + (&PlaceBase::Static(box Static{ kind: _, .. }), None) => { // 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_place( - dest, - PlaceContext::MutatingUse(MutatingUseContext::Store), - location - ); + let context = PlaceContext::MutatingUse(MutatingUseContext::Store); + self.visit_place_base(&dest.base, context, location); return; } } @@ -950,7 +980,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { match *candidate { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign(_, box Rvalue::Repeat( - Operand::Move(Place::Base(PlaceBase::Local(index))), + Operand::Move(Place { + base: PlaceBase::Local(index), + projection: None, + }), _ )) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); @@ -959,7 +992,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign( _, - box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index))) + box Rvalue::Ref(_, _, Place { + base: PlaceBase::Local(index), + projection: None, + }) ) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); } @@ -1043,6 +1079,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { fn visit_projection( &mut self, + place_base: &PlaceBase<'tcx>, proj: &Projection<'tcx>, context: PlaceContext, location: Location, @@ -1051,14 +1088,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { "visit_place_projection: proj={:?} context={:?} location={:?}", proj, context, location, ); - self.super_projection(proj, context, location); + self.super_projection(place_base, proj, context, location); match proj.elem { ProjectionElem::Deref => { if context.is_mutating_use() { // `not_const` errors out in const contexts self.not_const() } - let base_ty = proj.base.ty(self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; match self.mode { Mode::NonConstFn => {}, _ => { @@ -1082,7 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ProjectionElem::Subslice {..} | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = proj.base.ty(self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { match self.mode { @@ -1119,7 +1156,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { match *operand { Operand::Move(ref place) => { // Mark the consumed locals to indicate later drops are noops. - if let Place::Base(PlaceBase::Local(local)) = *place { + if let Place { + base: PlaceBase::Local(local), + projection: None, + } = *place { self.cx.per_local[NeedsDrop].remove(local); } } @@ -1135,16 +1175,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Rvalue::Ref(_, kind, ref place) = *rvalue { // Special-case reborrows. let mut reborrow_place = None; - if let Place::Projection(ref proj) = *place { + if let Some(ref proj) = place.projection { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(self.body, self.tcx).ty; + let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.sty { reborrow_place = Some(&proj.base); } } } - if let Some(place) = reborrow_place { + if let Some(proj) = reborrow_place { let ctx = match kind { BorrowKind::Shared => PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow, @@ -1159,7 +1199,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { MutatingUseContext::Borrow, ), }; - self.visit_place(place, ctx, location); + self.visit_place_base(&place.base, ctx, location); + if let Some(proj) = proj { + self.visit_projection(&place.base, proj, ctx, location); + } } else { self.super_rvalue(rvalue, location); } @@ -1428,7 +1471,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { unleash_miri!(self); // HACK(eddyb): emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. - let needs_drop = if let Place::Base(PlaceBase::Local(local)) = *place { + let needs_drop = if let Place { + base: PlaceBase::Local(local), + projection: None, + } = *place { if NeedsDrop::in_local(self, local) { Some(self.body.local_decls[local].source_info.span) } else { @@ -1658,7 +1704,10 @@ impl MirPass for QualifyAndPromoteConstants { let terminator = block.terminator_mut(); match terminator.kind { TerminatorKind::Drop { - location: Place::Base(PlaceBase::Local(index)), + location: Place { + base: PlaceBase::Local(index), + projection: None, + }, target, .. } => { diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 7b3cdc835ebb1..adba9097d12df 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -41,7 +41,10 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(Place::Base(PlaceBase::Local(_)), box Rvalue::Use(_)) => { + StatementKind::Assign(Place { + base: PlaceBase::Local(_), + projection: None, + }, 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 f12309c1d0a13..1fd865c42fcdb 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -118,8 +118,14 @@ fn each_block<'tcx, O>( }; assert!(args.len() == 1); let peek_arg_place = match args[0] { - mir::Operand::Copy(ref place @ mir::Place::Base(mir::PlaceBase::Local(_))) | - mir::Operand::Move(ref place @ mir::Place::Base(mir::PlaceBase::Local(_))) => Some(place), + mir::Operand::Copy(ref place @ mir::Place { + base: mir::PlaceBase::Local(_), + projection: None, + }) | + mir::Operand::Move(ref place @ mir::Place { + base: mir::PlaceBase::Local(_), + projection: None, + }) => Some(place), _ => None, }; @@ -162,7 +168,7 @@ fn each_block<'tcx, O>( if place == 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) { + match move_data.rev_lookup.find(peeking_at_place.as_place_ref()) { LookupResult::Exact(peek_mpi) => { let bit_state = on_entry.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", @@ -186,7 +192,7 @@ fn each_block<'tcx, O>( } } - let lhs_mpi = move_data.rev_lookup.find(place); + let lhs_mpi = move_data.rev_lookup.find(place.as_place_ref()); 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 6878eceb2a5db..6aceeebaea161 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -59,19 +59,27 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { - if let Place::Projection(ref proj) = *src_place { + if let Some(ref proj) = src_place.projection { if let ProjectionElem::ConstantIndex{offset: _, min_length: _, from_end: false} = proj.elem { // no need to transformation } else { - let place_ty = proj.base.ty(self.body, self.tcx).ty; + let place_ty = + Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).ty; 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, "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, + &src_place.base, + proj, + item_ty, + size as u32, + ); } } @@ -86,6 +94,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { fn uniform(&mut self, location: Location, dst_place: &Place<'tcx>, + base: &PlaceBase<'tcx>, proj: &Projection<'tcx>, item_ty: &'tcx ty::TyS<'tcx>, size: u32) { @@ -100,13 +109,20 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { Place::from(temp), Rvalue::Use( Operand::Move( - Place::Projection(box Projection{ - base: proj.base.clone(), - elem: ProjectionElem::ConstantIndex{ - offset: i, - min_length: size, - from_end: false} - })))); + Place { + base: base.clone(), + projection: Some(box Projection { + base: proj.base.clone(), + elem: ProjectionElem::ConstantIndex { + offset: i, + min_length: size, + from_end: false, + } + }), + } + ) + ) + ); temp }).collect(); self.patch.add_assign( @@ -130,12 +146,20 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { dst_place.clone(), Rvalue::Use( Operand::Move( - Place::Projection(box Projection{ - base: proj.base.clone(), - elem: ProjectionElem::ConstantIndex{ - offset: size - offset, - min_length: size, - from_end: false }})))); + Place { + base: base.clone(), + projection: Some(box Projection { + base: proj.base.clone(), + elem: ProjectionElem::ConstantIndex { + offset: size - offset, + min_length: size, + from_end: false, + }, + }), + } + ) + ) + ); } _ => {} } @@ -173,7 +197,10 @@ impl MirPass for RestoreSubsliceArrayMoveOut { if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind { if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval { let items : Vec<_> = items.iter().map(|item| { - if let Operand::Move(Place::Base(PlaceBase::Local(local))) = item { + if let Operand::Move(Place { + base: PlaceBase::Local(local), + projection: None, + }) = item { let local_use = &visitor.locals_use[*local]; let opt_index_and_place = Self::try_get_item_source(local_use, body); @@ -189,7 +216,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(body, tcx).ty; + let src_ty = + Place::ty_from(src_place.base, src_place.projection, body, tcx).ty; if let ty::Array(_, ref size_o) = src_ty.sty { size_o.assert_usize(tcx) } else { @@ -210,7 +238,7 @@ impl RestoreSubsliceArrayMoveOut { // indices is an integer interval. If all checks pass do the replacent. // items are Vec> fn check_and_patch<'tcx>(candidate: Location, - items: &[Option<(&LocalUse, u32, &Place<'tcx>)>], + items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>], opt_size: Option, patch: &mut MirPatch<'tcx>, dst_place: &Place<'tcx>) { @@ -218,6 +246,7 @@ impl RestoreSubsliceArrayMoveOut { if opt_size.is_some() && items.iter().all( |l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) { + let src_place = opt_src_place.unwrap(); let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect(); for i in 1..indices.len() { @@ -241,25 +270,39 @@ impl RestoreSubsliceArrayMoveOut { dst_place.clone(), Rvalue::Use( Operand::Move( - Place::Projection(box Projection{ - base: opt_src_place.unwrap().clone(), - elem: ProjectionElem::Subslice{ - from: min, to: size - max - 1}})))); + Place { + base: src_place.base.clone(), + projection: Some(box Projection { + base: src_place.projection.clone(), + elem: ProjectionElem::Subslice{ + from: min, to: size - max - 1}})}))); } } fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse, - body: &'a Body<'tcx>) -> Option<(u32, &'a Place<'tcx>)> { + body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> { if let Some(location) = local_use.first_use { let block = &body[location.block]; if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( - Place::Base(PlaceBase::Local(_)), - box Rvalue::Use(Operand::Move(Place::Projection(box Projection{ - ref base, elem: ProjectionElem::ConstantIndex{ - offset, min_length: _, from_end: false}})))) = statement.kind { - return Some((offset, base)) + Place { + base: PlaceBase::Local(_), + projection: None, + }, + box Rvalue::Use(Operand::Move(Place { + base, + projection: Some(box Projection { + base: proj_base, + elem: ProjectionElem::ConstantIndex { + offset, min_length: _, from_end: false + } + }), + }))) = &statement.kind { + return Some((*offset, PlaceRef { + base, + projection: proj_base, + })) } } } diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 6245d9c208b69..b8ef77da02e60 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -38,15 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<' where L: HasLocalDecls<'tcx>, { - let mut place = place; - while let &Place::Projection(box Projection { - ref base, ref elem - }) = place { - match *elem { + let mut place_projection = &place.projection; + + while let Some(proj) = place_projection { + match proj.elem { // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = base.ty(local_decls, tcx).ty; + let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty; match ty.sty { ty::Adt(def, _) if def.repr.packed() => { return true @@ -56,7 +55,7 @@ where } _ => {} } - place = base; + place_projection = &proj.base; } false diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index dac90d37275b4..61ad2ba8f5737 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -584,10 +584,13 @@ where (Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, - Place::Projection(Box::new(Projection { - base: Place::Base(PlaceBase::Local(cur)), - elem: ProjectionElem::Deref, - })) + Place { + base: PlaceBase::Local(cur), + projection: Some(Box::new(Projection { + base: None, + elem: ProjectionElem::Deref, + })), + } ), Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one)) } else {