From e9c41148c0c834d13d6f45bfd99c8f23781c5d31 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 30 Jul 2019 00:07:28 +0200 Subject: [PATCH 01/11] Convert Place's projection to a boxed slice --- src/librustc/mir/mod.rs | 290 +++++----------- src/librustc/mir/tcx.rs | 14 +- src/librustc/mir/visit.rs | 68 ++-- src/librustc_codegen_ssa/lib.rs | 1 + src/librustc_codegen_ssa/mir/analyze.rs | 26 +- src/librustc_codegen_ssa/mir/block.rs | 10 +- src/librustc_codegen_ssa/mir/operand.rs | 68 ++-- src/librustc_codegen_ssa/mir/place.rs | 35 +- src/librustc_codegen_ssa/mir/rvalue.rs | 2 +- src/librustc_codegen_ssa/mir/statement.rs | 2 +- src/librustc_mir/borrow_check/borrow_set.rs | 2 +- .../borrow_check/conflict_errors.rs | 44 +-- .../borrow_check/error_reporting.rs | 68 ++-- src/librustc_mir/borrow_check/mod.rs | 81 +++-- src/librustc_mir/borrow_check/move_errors.rs | 25 +- .../borrow_check/mutability_errors.rs | 111 +++--- .../borrow_check/nll/constraint_generation.rs | 14 +- .../borrow_check/nll/explain_borrow/mod.rs | 20 +- .../borrow_check/nll/type_check/mod.rs | 194 +++++------ src/librustc_mir/borrow_check/place_ext.rs | 88 ++--- .../borrow_check/places_conflict.rs | 318 +++++++++--------- src/librustc_mir/borrow_check/prefixes.rs | 203 ++++++----- src/librustc_mir/borrow_check/used_muts.rs | 2 +- src/librustc_mir/build/expr/as_place.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 28 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 18 +- src/librustc_mir/build/mod.rs | 6 +- src/librustc_mir/build/scope.rs | 6 +- .../dataflow/drop_flag_effects.rs | 11 +- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- .../dataflow/move_paths/builder.rs | 134 ++++---- src/librustc_mir/dataflow/move_paths/mod.rs | 30 +- src/librustc_mir/interpret/operand.rs | 50 ++- src/librustc_mir/interpret/place.rs | 62 ++-- src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/shim.rs | 8 +- src/librustc_mir/transform/add_retag.rs | 17 +- src/librustc_mir/transform/check_unsafety.rs | 226 ++++++------- src/librustc_mir/transform/const_prop.rs | 86 ++--- src/librustc_mir/transform/copy_prop.rs | 16 +- src/librustc_mir/transform/elaborate_drops.rs | 38 +-- src/librustc_mir/transform/generator.rs | 34 +- src/librustc_mir/transform/inline.rs | 32 +- src/librustc_mir/transform/instcombine.rs | 38 ++- src/librustc_mir/transform/promote_consts.rs | 12 +- src/librustc_mir/transform/qualify_consts.rs | 189 ++++++----- .../transform/qualify_min_const_fn.rs | 34 +- .../transform/remove_noop_landing_pads.rs | 2 +- src/librustc_mir/transform/rustc_peek.rs | 4 +- .../transform/uniform_array_move_out.rs | 180 +++++----- src/librustc_mir/util/alignment.rs | 9 +- src/librustc_mir/util/elaborate_drops.rs | 5 +- 53 files changed, 1399 insertions(+), 1570 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 18a5142208d2d..602ce12c37d81 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -32,7 +32,6 @@ use rustc_serialize::{Encodable, Decodable}; use smallvec::SmallVec; use std::borrow::Cow; use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::iter::FusedIterator; use std::ops::{Index, IndexMut}; use std::slice; use std::vec::IntoIter; @@ -1548,7 +1547,7 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(Statement<'_>, 56); +static_assert_size!(Statement<'_>, 64); impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -1717,7 +1716,7 @@ pub struct Place<'tcx> { pub base: PlaceBase<'tcx>, /// projection out of a place (access a field, deref a pointer, etc) - pub projection: Option>>, + pub projection: Box<[PlaceElem<'tcx>]>, } #[derive( @@ -1760,15 +1759,6 @@ impl_stable_hash_for!(struct Static<'tcx> { def_id }); -/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`. -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, -)] -pub struct Projection<'tcx> { - pub base: Option>>, - pub elem: PlaceElem<'tcx>, -} - #[derive( Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, )] @@ -1850,14 +1840,22 @@ 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>>, + pub projection: &'a [PlaceElem<'tcx>], } impl<'tcx> Place<'tcx> { - pub const RETURN_PLACE: Place<'tcx> = Place { - base: PlaceBase::Local(RETURN_PLACE), - projection: None, - }; + // FIXME change this back to a const when projection is a shared slice. + // + // pub const RETURN_PLACE: Place<'tcx> = Place { + // base: PlaceBase::Local(RETURN_PLACE), + // projection: &[], + // }; + pub fn return_place() -> Place<'tcx> { + Place { + base: PlaceBase::Local(RETURN_PLACE), + projection: Box::new([]), + } + } pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> { self.elem(ProjectionElem::Field(f, ty)) @@ -1883,9 +1881,13 @@ impl<'tcx> Place<'tcx> { } pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { + // FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore + let mut projection = self.projection.into_vec(); + projection.push(elem); + Place { base: self.base, - projection: Some(Box::new(Projection { base: self.projection, elem })), + projection: projection.into_boxed_slice(), } } @@ -1894,7 +1896,7 @@ impl<'tcx> Place<'tcx> { /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the /// same region of memory as its base. pub fn is_indirect(&self) -> bool { - self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect())) + self.projection.iter().any(|elem| elem.is_indirect()) } /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or @@ -1905,61 +1907,16 @@ impl<'tcx> Place<'tcx> { match self { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } | Place { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: box [ProjectionElem::Deref], } => Some(*local), _ => None, } } - /// 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 { - Place::iterate_over(&self.base, &self.projection, op) - } - - pub fn iterate_over( - place_base: &PlaceBase<'tcx>, - place_projection: &Option>>, - op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R, - ) -> R { - 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, - ) - } - } - } - - iterate_over2(place_base, place_projection, &Projections::Empty, op) - } - pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> { PlaceRef { base: &self.base, @@ -1972,7 +1929,7 @@ impl From for Place<'_> { fn from(local: Local) -> Self { Place { base: local.into(), - projection: None, + projection: Box::new([]), } } } @@ -1984,13 +1941,6 @@ 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. // @@ -1999,143 +1949,71 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> { match self { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } | PlaceRef { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [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`). -/// Created by `Place::iterate`. -/// -/// N.B., this particular impl strategy is not the most obvious. It was -/// chosen because it makes a measurable difference to NLL -/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. -pub enum Projections<'p, 'tcx> { - Empty, - - List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> }, -} - -impl<'p, 'tcx> Projections<'p, 'tcx> { - fn iter(&self) -> ProjectionsIter<'_, 'tcx> { - ProjectionsIter { value: self } - } -} - -impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> { - type Item = &'p Projection<'tcx>; - type IntoIter = ProjectionsIter<'p, 'tcx>; - - /// Converts a list of `Projection` components into an iterator; - /// this iterator yields up a never-ending stream of `Option<&Place>`. - /// These begin with the "innermost" projection and then with each - /// projection therefrom. So given a place like `a.b.c` it would - /// yield up: - /// - /// ```notrust - /// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ... - /// ``` - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -/// Iterator over components; see `Projections::iter` for more -/// information. -/// -/// N.B., this is not a *true* Rust iterator -- the code above just -/// manually invokes `next`. This is because we (sometimes) want to -/// keep executing even after `None` has been returned. -pub struct ProjectionsIter<'p, 'tcx> { - pub value: &'p Projections<'p, 'tcx>, -} - -impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> { - type Item = &'p Projection<'tcx>; - - fn next(&mut self) -> Option { - if let &Projections::List { projection, next } = self.value { - self.value = next; - Some(projection) - } else { - None - } - } -} - -impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {} - impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - self.iterate(|_place_base, place_projections| { - // FIXME: remove this collect once we have migrated to slices - let projs_vec: Vec<_> = place_projections.collect(); - for projection in projs_vec.iter().rev() { - match projection.elem { - ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { - write!(fmt, "(").unwrap(); - } - ProjectionElem::Deref => { - write!(fmt, "(*").unwrap(); - } - ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => {} + for elem in self.projection.iter().rev() { + match elem { + ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { + write!(fmt, "(").unwrap(); + } + ProjectionElem::Deref => { + write!(fmt, "(*").unwrap(); } + ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => {} } - }); + } - self.iterate(|place_base, place_projections| { - write!(fmt, "{:?}", place_base)?; + write!(fmt, "{:?}", self.base)?; - for projection in place_projections { - match projection.elem { - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, " as {})", name)?; - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, " as variant#{:?})", index)?; - } - ProjectionElem::Deref => { - write!(fmt, ")")?; - } - ProjectionElem::Field(field, ty) => { - write!(fmt, ".{:?}: {:?})", field.index(), ty)?; - } - ProjectionElem::Index(ref index) => { - write!(fmt, "[{:?}]", index)?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { - write!(fmt, "[{:?} of {:?}]", offset, min_length)?; - } - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { - write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; - } - ProjectionElem::Subslice { from, to } if to == 0 => { - write!(fmt, "[{:?}:]", from)?; - } - ProjectionElem::Subslice { from, to } if from == 0 => { - write!(fmt, "[:-{:?}]", to)?; - } - ProjectionElem::Subslice { from, to } => { - write!(fmt, "[{:?}:-{:?}]", from, to)?; - } + for elem in self.projection.iter() { + match elem { + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, " as {})", name)?; + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, " as variant#{:?})", index)?; + } + ProjectionElem::Deref => { + write!(fmt, ")")?; + } + ProjectionElem::Field(field, ty) => { + write!(fmt, ".{:?}: {:?})", field.index(), ty)?; + } + ProjectionElem::Index(ref index) => { + write!(fmt, "[{:?}]", index)?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => { + write!(fmt, "[{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { + write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::Subslice { from, to } if *to == 0 => { + write!(fmt, "[{:?}:]", from)?; + } + ProjectionElem::Subslice { from, to } if *from == 0 => { + write!(fmt, "[:-{:?}]", to)?; + } + ProjectionElem::Subslice { from, to } => { + write!(fmt, "[{:?}:-{:?}]", from, to)?; } } + } - Ok(()) - }) + Ok(()) } } @@ -3409,30 +3287,26 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { use crate::mir::ProjectionElem::*; - let base = self.base.fold_with(folder); - let elem = match self.elem { + match self { Deref => Deref, - Field(f, ref ty) => Field(f, ty.fold_with(folder)), - Index(ref v) => Index(v.fold_with(folder)), - ref elem => elem.clone(), - }; - - Projection { base, elem } + Field(f, ty) => Field(*f, ty.fold_with(folder)), + Index(v) => Index(v.fold_with(folder)), + elem => elem.clone(), + } } fn super_visit_with>(&self, visitor: &mut Vs) -> bool { use crate::mir::ProjectionElem::*; - self.base.visit_with(visitor) - || match self.elem { - Field(_, ref ty) => ty.visit_with(visitor), - Index(ref v) => v.visit_with(visitor), - _ => false, - } + match self { + Field(_, ty) => ty.visit_with(visitor), + Index(v) => v.visit_with(visitor), + _ => false, + } } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index e9f7636ba85ae..fbe25de0e762c 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -121,21 +121,19 @@ BraceStructTypeFoldableImpl! { impl<'tcx> Place<'tcx> { pub fn ty_from( base: &PlaceBase<'tcx>, - projection: &Option>>, + projection: &[PlaceElem<'tcx>], local_decls: &D, tcx: TyCtxt<'tcx> ) -> PlaceTy<'tcx> where D: HasLocalDecls<'tcx> { - Place::iterate_over(base, projection, |place_base, place_projections| { - let mut place_ty = place_base.ty(local_decls); + let mut place_ty = base.ty(local_decls); - for proj in place_projections { - place_ty = place_ty.projection_ty(tcx, &proj.elem); - } + for elem in projection.iter() { + place_ty = place_ty.projection_ty(tcx, elem); + } - place_ty - }) + place_ty } pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 821367e9ea12c..36aa891aaf4aa 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -152,18 +152,18 @@ macro_rules! make_mir_visitor { } fn visit_place_base(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, + base: & $($mutability)? PlaceBase<'tcx>, context: PlaceContext, location: Location) { - self.super_place_base(place_base, context, location); + self.super_place_base(base, context, location); } fn visit_projection(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, - place: & $($mutability)? Projection<'tcx>, + base: & $($mutability)? PlaceBase<'tcx>, + projection: & $($mutability)? [PlaceElem<'tcx>], context: PlaceContext, location: Location) { - self.super_projection(place_base, place, context, location); + self.super_projection(base, projection, context, location); } fn visit_constant(&mut self, @@ -685,7 +685,7 @@ macro_rules! make_mir_visitor { location: Location) { let mut context = context; - if place.projection.is_some() { + if !place.projection.is_empty() { context = if context.is_mutating_use() { PlaceContext::MutatingUse(MutatingUseContext::Projection) } else { @@ -695,9 +695,10 @@ macro_rules! make_mir_visitor { 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); - } + self.visit_projection(& $($mutability)? place.base, + & $($mutability)? place.projection, + context, + location); } fn super_place_base(&mut self, @@ -715,31 +716,34 @@ macro_rules! make_mir_visitor { } fn super_projection(&mut self, - place_base: & $($mutability)? PlaceBase<'tcx>, - proj: & $($mutability)? Projection<'tcx>, + base: & $($mutability)? PlaceBase<'tcx>, + projection: & $($mutability)? [PlaceElem<'tcx>], context: PlaceContext, location: Location) { - if let Some(box proj_base) = & $($mutability)? proj.base { - self.visit_projection(place_base, proj_base, context, location); - } - - match & $($mutability)? proj.elem { - ProjectionElem::Field(_field, ty) => { - self.visit_ty(ty, TyContext::Location(location)); - } - ProjectionElem::Index(local) => { - self.visit_local( - local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); - } - ProjectionElem::Deref | - ProjectionElem::Subslice { from: _, to: _ } | - ProjectionElem::ConstantIndex { offset: _, - min_length: _, - from_end: _ } | - ProjectionElem::Downcast(_, _) => { + if !projection.is_empty() { + let proj_len = projection.len(); + let proj_base = & $($mutability)? projection[..proj_len - 1]; + self.visit_projection(base, proj_base, context, location); + + let elem = & $($mutability)? projection[proj_len - 1]; + match elem { + ProjectionElem::Field(_field, ty) => { + self.visit_ty(ty, TyContext::Location(location)); + } + ProjectionElem::Index(local) => { + self.visit_local( + local, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location + ); + } + ProjectionElem::Deref | + ProjectionElem::Subslice { from: _, to: _ } | + ProjectionElem::ConstantIndex { offset: _, + min_length: _, + from_end: _ } | + ProjectionElem::Downcast(_, _) => { + } } } } diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 90bf964ceaa13..1708d7235b45b 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -4,6 +4,7 @@ #![feature(box_syntax)] #![feature(core_intrinsics)] #![feature(libc)] +#![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index e63f1b91dd7d5..5449dbdc913b8 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -105,7 +105,10 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { ) { let cx = self.fx.cx; - if let Some(proj) = place_ref.projection { + if let [.., elem] = place_ref.projection { + // FIXME(spastorino) include this in the pattern when stabilized + let proj_base = &place_ref.projection[..place_ref.projection.len() - 1]; + // Allow uses of projections that are ZSTs or from scalar fields. let is_consume = match context { PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | @@ -114,12 +117,12 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { }; if is_consume { let base_ty = - mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx()); + 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) + .projection_ty(cx.tcx(), elem) .ty; let elem_ty = self.fx.monomorphize(&elem_ty); let span = if let mir::PlaceBase::Local(index) = place_ref.base { @@ -131,7 +134,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { return; } - if let mir::ProjectionElem::Field(..) = proj.elem { + if let mir::ProjectionElem::Field(..) = elem { let layout = cx.spanned_layout_of(base_ty.ty, span); if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { // Recurse with the same context, instead of `Projection`, @@ -140,7 +143,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { self.process_place( &mir::PlaceRef { base: place_ref.base, - projection: &proj.base, + projection: proj_base, }, context, location, @@ -151,11 +154,11 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } // A deref projection only reads the pointer, never needs the place. - if let mir::ProjectionElem::Deref = proj.elem { + if let mir::ProjectionElem::Deref = elem { self.process_place( &mir::PlaceRef { base: place_ref.base, - projection: &proj.base, + projection: proj_base, }, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location @@ -168,7 +171,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { // visit_place API let mut context = context; - if place_ref.projection.is_some() { + if !place_ref.projection.is_empty() { context = if context.is_mutating_use() { PlaceContext::MutatingUse(MutatingUseContext::Projection) } else { @@ -177,10 +180,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } 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); - } + self.visit_projection(place_ref.base, place_ref.projection, context, location); } } @@ -196,7 +196,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *place { self.assign(index, location); let decl_span = self.fx.mir.local_decls[index].source_info.span; diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index c41e46398467a..915006938fe56 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.as_ref()); + self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref()); if let Ref(llval, _, align) = op.val { bx.load(llval, align) } else { @@ -612,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty, def_id: _, }), - projection: None, + projection: box [], } ) | mir::Operand::Move( @@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty, def_id: _, }), - projection: None, + projection: box [], } ) => { let param_env = ty::ParamEnv::reveal_all(); @@ -1105,7 +1105,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let dest = if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *dest { match self.locals[index] { LocalRef::Place(dest) => dest, @@ -1166,7 +1166,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) { if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *dst { match self.locals[index] { LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index a8ab3ea10ed16..58a13d685ddf9 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -384,47 +384,45 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option> { debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); - place_ref.iterate(|place_base, place_projection| { - if let mir::PlaceBase::Local(index) = place_base { - match self.locals[*index] { - LocalRef::Operand(Some(mut o)) => { - // Moves out of scalar and scalar pair fields are trivial. - for proj in place_projection { - match proj.elem { - mir::ProjectionElem::Field(ref f, _) => { - o = o.extract_field(bx, f.index()); - } - mir::ProjectionElem::Index(_) | - mir::ProjectionElem::ConstantIndex { .. } => { - // ZSTs don't require any actual memory access. - // FIXME(eddyb) deduplicate this with the identical - // checks in `codegen_consume` and `extract_field`. - let elem = o.layout.field(bx.cx(), 0); - if elem.is_zst() { - o = OperandRef::new_zst(bx, elem); - } else { - return None; - } + if let mir::PlaceBase::Local(index) = place_ref.base { + match self.locals[*index] { + LocalRef::Operand(Some(mut o)) => { + // Moves out of scalar and scalar pair fields are trivial. + for elem in place_ref.projection.iter() { + match elem { + mir::ProjectionElem::Field(ref f, _) => { + o = o.extract_field(bx, f.index()); + } + mir::ProjectionElem::Index(_) | + mir::ProjectionElem::ConstantIndex { .. } => { + // ZSTs don't require any actual memory access. + // FIXME(eddyb) deduplicate this with the identical + // checks in `codegen_consume` and `extract_field`. + let elem = o.layout.field(bx.cx(), 0); + if elem.is_zst() { + o = OperandRef::new_zst(bx, elem); + } else { + return None; } - _ => return None, } + _ => return None, } - - Some(o) - } - LocalRef::Operand(None) => { - bug!("use of {:?} before def", place_ref); - } - LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { - // watch out for locals that do not have an - // alloca; they are handled somewhat differently - None } + + Some(o) + } + LocalRef::Operand(None) => { + bug!("use of {:?} before def", place_ref); + } + LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { + // watch out for locals that do not have an + // alloca; they are handled somewhat differently + None } - } else { - None } - }) + } else { + None + } } pub fn codegen_consume( diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index b8e10d3430292..df90da7ee8fae 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -449,7 +449,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let result = match &place_ref { mir::PlaceRef { base: mir::PlaceBase::Local(index), - projection: None, + projection: [], } => { match self.locals[*index] { LocalRef::Place(place) => { @@ -469,7 +469,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { kind: mir::StaticKind::Promoted(promoted, substs), def_id, }), - projection: None, + projection: [], } => { let param_env = ty::ParamEnv::reveal_all(); let instance = Instance::new(*def_id, self.monomorphize(substs)); @@ -504,7 +504,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { kind: mir::StaticKind::Static, def_id, }), - projection: None, + projection: [], } => { // NB: The layout of a static may be unsized as is the case when working // with a static that is an extern_type. @@ -514,11 +514,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }, mir::PlaceRef { base, - projection: Some(box mir::Projection { - base: proj_base, - elem: mir::ProjectionElem::Deref, - }), + projection: [.., mir::ProjectionElem::Deref], } => { + let proj_base = &place_ref.projection[..place_ref.projection.len() - 1]; + // Load the pointer from its location. self.codegen_consume(bx, &mir::PlaceRef { base, @@ -527,22 +526,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::PlaceRef { base, - projection: Some(projection), + projection: [.., elem], } => { + let proj_base = &place_ref.projection[..place_ref.projection.len() - 1]; + // FIXME turn this recursion into iteration let cg_base = self.codegen_place(bx, &mir::PlaceRef { base, - projection: &projection.base, + projection: proj_base, }); - match projection.elem { + match elem { mir::ProjectionElem::Deref => bug!(), mir::ProjectionElem::Field(ref field, _) => { cg_base.project_field(bx, field.index()) } mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy( - mir::Place::from(index) + mir::Place::from(*index) ); let index = self.codegen_operand(bx, index); let llindex = index.immediate(); @@ -551,27 +552,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset as u64); + let lloffset = bx.cx().const_usize(*offset as u64); cg_base.project_index(bx, lloffset) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset as u64); + let lloffset = bx.cx().const_usize(*offset as u64); let lllen = cg_base.len(bx.cx()); let llindex = bx.sub(lllen, lloffset); cg_base.project_index(bx, llindex) } mir::ProjectionElem::Subslice { from, to } => { let mut subslice = cg_base.project_index(bx, - bx.cx().const_usize(from as u64)); + bx.cx().const_usize(*from as u64)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty) - .projection_ty(tcx, &projection.elem).ty; + .projection_ty(tcx, elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(), - bx.cx().const_usize((from as u64) + (to as u64)))); + bx.cx().const_usize((*from as u64) + (*to as u64)))); } // Cast the place pointer type to the new @@ -582,7 +583,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { subslice } mir::ProjectionElem::Downcast(_, v) => { - cg_base.project_downcast(bx, v) + cg_base.project_downcast(bx, *v) } } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index e0ad2527229ba..0a932bc3e1574 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -522,7 +522,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // because codegen_place() panics if Local is operand. if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::Array(_, n) = op.layout.ty.sty { diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 594f45c833758..b1bc57c2e90ec 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::StatementKind::Assign(ref place, ref rvalue) => { if let mir::Place { base: mir::PlaceBase::Local(index), - projection: None, + projection: box [], } = *place { match self.locals[index] { LocalRef::Place(cg_dest) => { diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index c9e6e7f70a2b4..db19cbc3175f8 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -317,7 +317,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> { // so extract `temp`. let temp = if let &mir::Place { base: mir::PlaceBase::Local(temp), - projection: None, + projection: box [], } = assigned_place { temp } else { diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index bfc7050ebf71c..a6f7c8f227c99 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -2,8 +2,8 @@ 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, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, + LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, + Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashSet; @@ -244,7 +244,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } let span = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = place { let decl = &self.body.local_decls[*local]; Some(decl.source_info.span) @@ -614,9 +614,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = first_borrowed_place; - let mut current = projection; + for (i, elem) in projection.iter().enumerate().rev() { + let base_proj = &projection[..i]; - while let Some(box Projection { base: base_proj, elem }) = current { match elem { ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => { return Some((PlaceRef { @@ -624,7 +624,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection: base_proj, }, field)); }, - _ => current = base_proj, + _ => {}, } } None @@ -637,9 +637,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection, } = second_borrowed_place; - let mut current = projection; + for (i, elem) in projection.iter().enumerate().rev() { + let proj_base = &projection[..i]; - while let Some(box Projection { base: proj_base, elem }) = current { if let ProjectionElem::Field(field, _) = elem { if let Some(union_ty) = union_ty(base, proj_base) { if field != target_field @@ -660,8 +660,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - - current = proj_base; } None }) @@ -707,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.var_or_use(); - assert!(root_place.projection.is_none()); + assert!(root_place.projection.is_empty()); let proper_span = match root_place.base { PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span, _ => drop_span, @@ -716,7 +714,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.access_place_error_reported .contains(&(Place { base: root_place.base.clone(), - projection: root_place.projection.clone(), + projection: root_place.projection.to_vec().into_boxed_slice(), }, borrow_span)) { debug!( @@ -729,7 +727,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.access_place_error_reported .insert((Place { base: root_place.base.clone(), - projection: root_place.projection.clone(), + projection: root_place.projection.to_vec().into_boxed_slice(), }, borrow_span)); if let StorageDeadOrDrop::Destructor(dropped_ty) = @@ -1107,7 +1105,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let local_kind = match borrow.borrowed_place { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } => { match self.body.local_kind(local) { LocalKind::ReturnPointer @@ -1136,7 +1134,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .unwrap(); let local = if let PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } = root_place { local } else { @@ -1446,7 +1444,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) { let (from_arg, local_decl) = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *err_place { if let LocalKind::Arg = self.body.local_kind(local) { (true, Some(&self.body.local_decls[local])) @@ -1519,10 +1517,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> { let tcx = self.infcx.tcx; match place.projection { - None => { + [] => { StorageDeadOrDrop::LocalStorageDead } - Some(box Projection { ref base, ref elem }) => { + [.., elem] => { + // FIXME(spastorino) revisit when we get rid of Box + let base = &place.projection[..place.projection.len() - 1]; + + // FIXME(spastorino) make this iterate let base_access = self.classify_drop_access_kind(PlaceRef { base: place.base, projection: base, @@ -1609,7 +1611,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut target = *match reservation { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } if self.body.local_kind(*local) == LocalKind::Temp => local, _ => return None, }; @@ -1625,7 +1627,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let StatementKind::Assign( Place { base: PlaceBase::Local(assigned_to), - projection: None, + projection: box [], }, box rvalue ) = &stmt.kind { @@ -1753,7 +1755,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let TerminatorKind::Call { destination: Some((Place { base: PlaceBase::Local(assigned_to), - projection: None, + projection: box [], }, _)), args, .. diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 9f25e98052ec4..1fbedc49ecf3f 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -152,7 +152,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { self.append_local_to_string(*local, buf)?; } @@ -162,7 +162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => { buf.push_str("promoted"); } @@ -173,15 +173,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id, .. }), - projection: None, + projection: [], } => { buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string()); } PlaceRef { base, - projection: Some(ref proj), + projection: [.., elem], } => { - match proj.elem { + let proj_base = &place.projection[..place.projection.len() - 1]; + + match elem { ProjectionElem::Deref => { let upvar_field_projection = self.is_upvar_field_projection(place); @@ -199,20 +201,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, &including_downcast, )?; } else { - match (&proj.base, base) { - (None, PlaceBase::Local(local)) => { + match (proj_base, base) { + ([], PlaceBase::Local(local)) => { if self.body.local_decls[*local].is_ref_for_guard() { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -224,7 +226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -238,7 +240,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -253,7 +255,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -275,12 +277,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { let field_name = self.describe_field(PlaceRef { base, - projection: &proj.base, - }, field); + projection: proj_base, + }, *field); self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -295,14 +297,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, &including_downcast, )?; buf.push_str("["); - if self.append_local_to_string(index, buf).is_err() { + if self.append_local_to_string(*index, buf).is_err() { buf.push_str("_"); } buf.push_str("]"); @@ -315,7 +317,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.append_place_to_string( PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, buf, autoderef, @@ -349,28 +351,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { let local = &self.body.local_decls[*local]; self.describe_field_from_ty(&local.ty, field, None) } PlaceRef { base: PlaceBase::Static(static_), - projection: None, + projection: [], } => self.describe_field_from_ty(&static_.ty, field, None), PlaceRef { base, - projection: Some(proj), - } => match proj.elem { - ProjectionElem::Deref => self.describe_field(PlaceRef { - base, - projection: &proj.base, - }, field), + projection: [.., elem], + } => match elem { + ProjectionElem::Deref => { + let proj_base = &place.projection[..place.projection.len() - 1]; + + self.describe_field(PlaceRef { + base, + projection: proj_base, + }, field) + } ProjectionElem::Downcast(_, variant_index) => { 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)) + self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) } ProjectionElem::Field(_, field_type) => { self.describe_field_from_ty(&field_type, field, None) @@ -378,9 +384,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { + let proj_base = &place.projection[..place.projection.len() - 1]; + self.describe_field(PlaceRef { base, - projection: &proj.base, + projection: proj_base, }, field) } }, @@ -445,7 +453,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id, .. }), - projection: None, + projection: [], } = 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)); @@ -830,7 +838,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(&Statement { kind: StatementKind::Assign(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, _), .. }) => local, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 9ad7cbc478bb0..041047bf7cdc8 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -10,10 +10,10 @@ 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, PlaceRef, - Static, StaticKind + ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem, + PlaceRef, Static, StaticKind }; -use rustc::mir::{Field, Projection, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; +use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt}; @@ -905,7 +905,7 @@ enum InitializationRequiringAction { struct RootPlace<'d, 'tcx> { place_base: &'d PlaceBase<'tcx>, - place_projection: &'d Option>>, + place_projection: &'d [PlaceElem<'tcx>], is_local_mutation_allowed: LocalMutationIsAllowed, } @@ -1191,7 +1191,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // before (at this point in the flow). if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = place_span.0 { if let Mutability::Not = self.body.local_decls[*local].mutability { // check for reassignments to immutable local variables @@ -1331,7 +1331,7 @@ 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>| { - if place.projection.is_some() { + if !place.projection.is_empty() { if let Some(field) = this.is_upvar_field_projection(place.as_ref()) { this.used_mut_upvars.push(field); } @@ -1346,11 +1346,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match *operand { Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) | Operand::Copy(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) if self.body.local_decls[local].is_user_variable.is_none() => { if self.body.local_decls[local].ty.is_mutable_ptr() { // The variable will be marked as mutable by the borrow. @@ -1468,7 +1468,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // FIXME: allow thread-locals to borrow other thread locals? - assert!(root_place.projection.is_none()); + assert!(root_place.projection.is_empty()); let (might_be_alive, will_be_dropped) = match root_place.base { PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), @@ -1756,13 +1756,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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_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 { + for (i, elem) in place.projection.iter().enumerate().rev() { + match elem { ProjectionElem::Index(_/*operand*/) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. @@ -1774,11 +1771,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // assigning to (*P) requires P to be initialized ProjectionElem::Deref => { + let proj_base = &place.projection[..i]; + self.check_if_full_path_is_moved( location, InitializationRequiringAction::Use, (PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }, span), flow_state); // (base initialized; no need to // recur further) @@ -1791,18 +1790,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Field(..) => { + let proj_base = &place.projection[..i]; // 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; + let base_ty = Place::ty_from(&place.base, proj_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, + projection: proj_base, }, span), flow_state); // (base initialized; no need to @@ -1815,7 +1815,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::Adt(..) | ty::Tuple(..) => { check_parent_of_field(self, location, PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }, span, flow_state); if let PlaceBase::Local(local) = place.base { @@ -1835,8 +1835,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - - place_projection = base; } fn check_parent_of_field<'cx, 'tcx>( @@ -2084,7 +2082,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match root_place { RootPlace { place_base: PlaceBase::Local(local), - place_projection: None, + place_projection: [], is_local_mutation_allowed, } => { // If the local may have been initialized, and it is now currently being @@ -2103,7 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } => {} RootPlace { place_base, - place_projection: place_projection @ Some(_), + place_projection: place_projection @ [.., _], is_local_mutation_allowed: _, } => { if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -2115,7 +2113,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } RootPlace { place_base: PlaceBase::Static(..), - place_projection: None, + place_projection: [], is_local_mutation_allowed: _, } => {} } @@ -2131,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { let local = &self.body.local_decls[*local]; match local.mutability { @@ -2162,7 +2160,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => Ok(RootPlace { place_base: place.base, @@ -2175,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id, .. }), - projection: None, + projection: [], } => { if !self.infcx.tcx.is_mutable_static(*def_id) { Err(place) @@ -2189,12 +2187,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } PlaceRef { base: _, - projection: Some(proj), + projection: [.., elem], } => { - match proj.elem { + let proj_base = &place.projection[..place.projection.len() - 1]; + + match elem { ProjectionElem::Deref => { let base_ty = - Place::ty_from(place.base, &proj.base, self.body, self.infcx.tcx).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 { @@ -2216,7 +2216,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, mode) } } @@ -2240,7 +2240,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ if base_ty.is_box() => { self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, is_local_mutation_allowed) } // Deref should only be for reference, pointers or boxes @@ -2297,7 +2297,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // ``` let _ = self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, is_local_mutation_allowed)?; Ok(RootPlace { place_base: place.base, @@ -2309,7 +2309,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { self.is_mutable(PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }, is_local_mutation_allowed) } } @@ -2326,21 +2326,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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; + if let [.., ProjectionElem::Deref] = place_projection { + place_projection = &place_projection[..place_projection.len() - 1]; by_ref = true; } match place_projection { - Some(box Projection { - base, - elem: ProjectionElem::Field(field, _ty), - }) => { + [.., ProjectionElem::Field(field, _ty)] => { + let base = &place_projection[..place_projection.len() - 1]; let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty; + 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) { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 0d13db2f5a413..d346a4cdfa21a 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -91,7 +91,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(StatementKind::Assign( Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, box Rvalue::Use(Operand::Move(move_from)), )) = self.body.basic_blocks()[location.block] @@ -274,16 +274,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { place: &Place<'tcx>, span: Span ) -> DiagnosticBuilder<'a> { - let description = if place.projection.is_none() { + let description = if place.projection.is_empty() { format!("static item `{}`", self.describe_place(place.as_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, + projection: &place.projection[..1], }; format!( @@ -310,16 +306,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .find_map(|p| self.is_upvar_field_projection(p)); let deref_base = match deref_target_place.projection { - Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef { - base: &deref_target_place.base, - projection: base, - }, + box [.., ProjectionElem::Deref] => { + let proj_base = + &deref_target_place.projection[..deref_target_place.projection.len() - 1]; + + PlaceRef { + base: &deref_target_place.base, + projection: proj_base, + } + } _ => bug!("deref_target_place is not a deref projection"), }; if let PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } = deref_base { let decl = &self.body.local_decls[*local]; if decl.is_ref_for_guard() { diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 8f2ce80aafa22..dbc1d1700933f 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -2,7 +2,7 @@ use rustc::hir; use rustc::hir::Node; use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body}; use rustc::mir::{ - Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind + Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind }; use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; @@ -47,12 +47,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match the_place_err { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => { item_msg = format!("`{}`", access_place_desc.unwrap()); if let Place { base: PlaceBase::Local(_), - projection: None, + projection: box [], } = access_place { reason = ", as it is not declared as mutable".to_string(); } else { @@ -65,14 +65,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: - Some(box Projection { - base, - elem: ProjectionElem::Field(upvar_index, _), - }), + projection: [.., ProjectionElem::Field(upvar_index, _)], } => { + let proj_base = &the_place_err.projection[..the_place_err.projection.len() - 1]; + debug_assert!(is_closure_or_generator( - Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty + Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); @@ -86,14 +84,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: - Some(box Projection { - base, - elem: ProjectionElem::Deref, - }), + projection: [.., ProjectionElem::Deref], } => { + // FIXME(spastorino) once released use box [base @ .., ProjectionElem::Deref] + let base = &the_place_err.projection[..the_place_err.projection.len() - 1]; + if the_place_err.base == &PlaceBase::Local(Local::new(1)) && - base.is_none() && + base.is_empty() && !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); @@ -114,7 +111,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ", as `Fn` closures cannot mutate their captured variables".to_string() } } else if { - if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) { + if let (PlaceBase::Local(local), []) = (&the_place_err.base, base) { self.body.local_decls[*local].is_ref_for_guard() } else { false @@ -151,7 +148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => unreachable!(), PlaceRef { @@ -161,11 +158,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { def_id, .. }), - projection: None, + projection: [], } => { if let Place { base: PlaceBase::Static(_), - projection: None, + projection: box [], } = access_place { item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); reason = String::new(); @@ -178,33 +175,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: - Some(box Projection { - base: _, - elem: ProjectionElem::Index(_), - }), + projection: [.., ProjectionElem::Index(_)], } | PlaceRef { base: _, - projection: - Some(box Projection { - base: _, - elem: ProjectionElem::ConstantIndex { .. }, - }), + projection: [.., ProjectionElem::ConstantIndex { .. }], } | PlaceRef { base: _, - projection: Some(box Projection { - base: _, - elem: ProjectionElem::Subslice { .. }, - }), + projection: [.., ProjectionElem::Subslice { .. }], } | PlaceRef { base: _, - projection: Some(box Projection { - base: _, - elem: ProjectionElem::Downcast(..), - }), + projection: [.., ProjectionElem::Downcast(..)], } => bug!("Unexpected immutable place."), } @@ -262,22 +245,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // after the field access). 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::Deref, - }), + projection: [.., + ProjectionElem::Deref, + ProjectionElem::Field(field, _), + ProjectionElem::Deref, + ], } => { + let base_proj = &the_place_err.projection[..the_place_err.projection.len() - 3]; + err.span_label(span, format!("cannot {ACT}", ACT = act)); if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty, + Place::ty_from(base, base_proj, self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -292,7 +272,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Suggest removing a `&mut` from the use of a mutable reference. PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } if { self.body.local_decls.get(*local).map(|local_decl| { if let ClearCrossCrate::Set( @@ -328,7 +308,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // variable) mutations... PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } 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`, @@ -349,13 +329,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Also suggest adding mut for upvars PlaceRef { base, - projection: Some(box Projection { - base: proj_base, - elem: ProjectionElem::Field(upvar_index, _), - }), + projection: [.., ProjectionElem::Field(upvar_index, _)], } => { + let proj_base = &the_place_err.projection[..the_place_err.projection.len() - 1]; + debug_assert!(is_closure_or_generator( - Place::ty_from(&base, &proj_base, 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)); @@ -385,7 +364,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // a local variable, then just suggest the user remove it. PlaceRef { base: PlaceBase::Local(_), - projection: None, + projection: [], } if { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { snippet.starts_with("&mut ") @@ -400,10 +379,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], } if { if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = self.body.local_decls[*local].is_user_variable @@ -427,10 +403,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // arbitrary base for the projection? PlaceRef { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], } if self.body.local_decls[*local].is_user_variable.is_some() => { let local_decl = &self.body.local_decls[*local]; @@ -510,10 +483,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base, - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: [ProjectionElem::Deref], // FIXME document what is this 1 magic number about } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => @@ -527,10 +497,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: Some(box Projection { - base: _, - elem: ProjectionElem::Deref, - }), + projection: [.., ProjectionElem::Deref], } => { err.span_label(span, format!("cannot {ACT}", ACT = act)); diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 5c230913a0da3..1e5f613aedc23 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -8,9 +8,8 @@ use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{ - BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection, - ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, - UserTypeProjection, + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue, + SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty}; @@ -229,14 +228,11 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { match place { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } | Place { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }), + projection: box [ProjectionElem::Deref], } => { debug!( "Recording `killed` facts for borrows of local={:?} at location={:?}", @@ -261,7 +257,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { Place { base: PlaceBase::Local(local), - projection: Some(_), + projection: box [.., _], } => { // Kill conflicting borrows of the innermost local. debug!( 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 aba3ef1cbbfc9..ad68b4bc054bb 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -274,7 +274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Place { base: PlaceBase::Local(borrowed_local), - projection: None, + projection: box [], } = place { if body.local_decls[*borrowed_local].name.is_some() && local != *borrowed_local @@ -495,11 +495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Operand::Constant(c) => c.span, Operand::Copy(Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], }) => { let local_decl = &self.body.local_decls[*l]; if local_decl.name.is_none() { @@ -543,7 +543,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut target = if let Some(&Statement { kind: StatementKind::Assign(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, _), .. }) = stmt @@ -583,11 +583,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Use(operand) => match operand { Operand::Copy(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) if *from == target => { @@ -602,11 +602,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) => match operand { Operand::Copy(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(from), - projection: None, + projection: box [], }) if *from == target => { @@ -639,7 +639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let TerminatorKind::Call { destination: Some((Place { base: PlaceBase::Local(dest), - projection: None, + projection: box [], }, block)), args, .. @@ -653,7 +653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let found_target = args.iter().any(|arg| { if let Operand::Move(Place { base: PlaceBase::Local(potential), - projection: None, + projection: box [], }) = arg { *potential == target } else { 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 da1f64b05151b..599472958f4fc 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -421,107 +421,104 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); - place.iterate(|place_base, place_projection| { - let mut place_ty = match place_base { - PlaceBase::Local(index) => - PlaceTy::from_ty(self.body.local_decls[*index].ty), - PlaceBase::Static(box Static { kind, ty: sty, def_id }) => { - let sty = self.sanitize_type(place, sty); - let check_err = - |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, - place: &Place<'tcx>, - ty, - sty| { - if let Err(terr) = verifier.cx.eq_types( - sty, - ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - verifier, - place, - "bad promoted type ({:?}: {:?}): {:?}", - ty, - sty, - terr - ); - }; + let mut place_ty = match &place.base { + PlaceBase::Local(index) => + PlaceTy::from_ty(self.body.local_decls[*index].ty), + PlaceBase::Static(box Static { kind, ty: sty, def_id }) => { + let sty = self.sanitize_type(place, sty); + let check_err = + |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, + place: &Place<'tcx>, + ty, + sty| { + if let Err(terr) = verifier.cx.eq_types( + sty, + ty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + verifier, + place, + "bad promoted type ({:?}: {:?}): {:?}", + ty, + sty, + terr + ); }; - match kind { - StaticKind::Promoted(promoted, _) => { - if !self.errors_reported { - let promoted_body = &self.promoted[*promoted]; - self.sanitize_promoted(promoted_body, location); - - let promoted_ty = promoted_body.return_ty(); - check_err(self, place, promoted_ty, sty); - } + }; + match kind { + StaticKind::Promoted(promoted, _) => { + if !self.errors_reported { + let promoted_body = &self.promoted[*promoted]; + self.sanitize_promoted(promoted_body, location); + + let promoted_ty = promoted_body.return_ty(); + check_err(self, place, promoted_ty, sty); } - StaticKind::Static => { - let ty = self.tcx().type_of(*def_id); - let ty = self.cx.normalize(ty, location); + } + StaticKind::Static => { + let ty = self.tcx().type_of(*def_id); + let ty = self.cx.normalize(ty, location); - check_err(self, place, ty, sty); - } + check_err(self, place, ty, sty); } - PlaceTy::from_ty(sty) } - }; + PlaceTy::from_ty(sty) + } + }; - // FIXME use place_projection.is_empty() when is available - 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(..), - .. - }), - projection: None, - } => true, - _ => false, - }; + if place.projection.is_empty() { + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + let is_promoted = match place { + Place { + base: PlaceBase::Static(box Static { + kind: StaticKind::Promoted(..), + .. + }), + projection: box [], + } => true, + _ => false, + }; - if !is_promoted { - let tcx = self.tcx(); - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.ty, &[]), - }; + if !is_promoted { + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().copy_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), + }; - // In order to have a Copy operand, the type T of the - // value must be Copy. Note that we prove that T: Copy, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from Copy impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use Copy before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement Copy, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } + // In order to have a Copy operand, the type T of the + // value must be Copy. Note that we prove that T: Copy, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from Copy impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use Copy before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement Copy, then + // it must. + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); } } + } - for proj in place_projection { - if place_ty.variant_index.is_none() { - if place_ty.ty.references_error() { - assert!(self.errors_reported); - return PlaceTy::from_ty(self.tcx().types.err); - } + for elem in place.projection.iter() { + if place_ty.variant_index.is_none() { + if place_ty.ty.references_error() { + assert!(self.errors_reported); + return PlaceTy::from_ty(self.tcx().types.err); } - place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location) } + place_ty = self.sanitize_projection(place_ty, elem, place, location) + } - place_ty - }) + place_ty } fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { @@ -1354,7 +1351,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let category = match *place { Place { base: PlaceBase::Local(RETURN_PLACE), - projection: None, + projection: box [], } => if let BorrowCheckContext { universal_regions: UniversalRegions { @@ -1373,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }, Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], } if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } @@ -1660,7 +1657,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let category = match *dest { Place { base: PlaceBase::Local(RETURN_PLACE), - projection: None, + projection: box [], } => { if let BorrowCheckContext { universal_regions: @@ -1682,7 +1679,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], } if !body.local_decls[l].is_user_variable.is_some() => { ConstraintCategory::Boring } @@ -2416,19 +2413,18 @@ 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_projection = &borrowed_place.projection; - debug!( "add_reborrow_constraint({:?}, {:?}, {:?})", location, borrow_region, borrowed_place ); - while let Some(box proj) = borrowed_projection { - debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection); + for (i, elem) in borrowed_place.projection.iter().enumerate().rev() { + debug!("add_reborrow_constraint - iteration {:?}", elem); + let proj_base = &borrowed_place.projection[..i]; - match proj.elem { + match elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, 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 { @@ -2490,10 +2486,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // other field access } } - - // The "propagate" case. We need to check that our base is valid - // for the borrow's lifetime. - borrowed_projection = &proj.base; } } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 5caba637ccc4a..50067345c65ee 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -25,55 +25,55 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool { - self.iterate(|place_base, place_projection| { - let ignore = match place_base { - // If a local variable is immutable, then we only need to track borrows to guard - // against two kinds of errors: - // * The variable being dropped while still borrowed (e.g., because the fn returns - // a reference to a local variable) - // * The variable being moved while still borrowed - // - // In particular, the variable cannot be mutated -- the "access checks" will fail -- - // so we don't have to worry about mutation while borrowed. - PlaceBase::Local(index) => { - match locals_state_at_exit { - LocalsStateAtExit::AllAreInvalidated => false, - LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { - let ignore = !has_storage_dead_or_moved.contains(*index) && - body.local_decls[*index].mutability == Mutability::Not; - debug!("ignore_borrow: local {:?} => {:?}", index, ignore); - ignore - } + let ignore = match self.base { + // If a local variable is immutable, then we only need to track borrows to guard + // against two kinds of errors: + // * The variable being dropped while still borrowed (e.g., because the fn returns + // a reference to a local variable) + // * The variable being moved while still borrowed + // + // In particular, the variable cannot be mutated -- the "access checks" will fail -- + // so we don't have to worry about mutation while borrowed. + PlaceBase::Local(index) => { + match locals_state_at_exit { + LocalsStateAtExit::AllAreInvalidated => false, + LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { + let ignore = !has_storage_dead_or_moved.contains(index) && + body.local_decls[index].mutability == Mutability::Not; + debug!("ignore_borrow: local {:?} => {:?}", index, ignore); + ignore } } - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => - false, - PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { - tcx.is_mutable_static(*def_id) - } - }; + } + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => + false, + PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { + tcx.is_mutable_static(def_id) + } + }; - for proj in place_projection { - if proj.elem == ProjectionElem::Deref { - 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 - // therefore not significant. In particular, - // there is nothing the user can do to the - // original path that would invalidate the - // newly created reference -- and if there - // were, then the user could have copied the - // original path into a new variable and - // borrowed *that* one, leaving the original - // path unborrowed. - ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true, - _ => {} - } + for (i, elem) in self.projection.iter().enumerate() { + let proj_base = &self.projection[..i]; + + if *elem == ProjectionElem::Deref { + let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty; + match ty.sty { + // For both derefs of raw pointers and `&T` + // references, the original path is `Copy` and + // therefore not significant. In particular, + // there is nothing the user can do to the + // original path that would invalidate the + // newly created reference -- and if there + // were, then the user could have copied the + // original path into a new variable and + // borrowed *that* one, leaving the original + // path unborrowed. + ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true, + _ => {} } } + } - ignore - }) + ignore } } diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 4f469174b392d..dafa0b6631fe2 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -3,8 +3,7 @@ use crate::borrow_check::Overlap; use crate::borrow_check::{Deep, Shallow, AccessDepth}; use rustc::hir; use rustc::mir::{ - Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter, - StaticKind, + Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind, }; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -67,39 +66,35 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( // it's so common that it's a speed win to check for it first. if let Place { base: PlaceBase::Local(l1), - projection: None, + projection: box [], } = borrow_place { if let PlaceRef { base: PlaceBase::Local(l2), - projection: None, + projection: [], } = access_place { return l1 == l2; } } - borrow_place.iterate(|borrow_base, borrow_projections| { - access_place.iterate(|access_base, access_projections| { - place_components_conflict( - tcx, - param_env, - body, - (borrow_base, borrow_projections), - borrow_kind, - (access_base, access_projections), - access, - bias, - ) - }) - }) + place_components_conflict( + tcx, + param_env, + body, + borrow_place, + borrow_kind, + access_place, + access, + bias, + ) } fn place_components_conflict<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, - borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), + borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, - access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), + access_place: PlaceRef<'_, 'tcx>, access: AccessDepth, bias: PlaceConflictBias, ) -> bool { @@ -145,8 +140,8 @@ fn place_components_conflict<'tcx>( // and either equal or disjoint. // - If we did run out of access, the borrow can access a part of it. - let borrow_base = borrow_projections.0; - let access_base = access_projections.0; + let borrow_base = &borrow_place.base; + let access_base = access_place.base; match place_base_conflict(tcx, param_env, borrow_base, access_base) { Overlap::Arbitrary => { @@ -163,147 +158,157 @@ fn place_components_conflict<'tcx>( } } - let mut borrow_projections = borrow_projections.1; - let mut access_projections = access_projections.1; - - loop { - // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - if let Some(borrow_c) = borrow_projections.next() { - debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); + // loop invariant: borrow_c is always either equal to access_c or disjoint from it. + for (i, (borrow_c, access_c)) in + borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate() + { + debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); + let borrow_proj_base = &borrow_place.projection[..i]; - if let Some(access_c) = access_projections.next() { - debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); + debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); - // Borrow and access path both have more components. - // - // Examples: - // - // - borrow of `a.(...)`, access to `a.(...)` - // - borrow of `a.(...)`, access to `b.(...)` - // - // Here we only see the components we have checked so - // far (in our examples, just the first component). We - // check whether the components being borrowed vs - // accessed are disjoint (as in the second example, - // but not the first). - 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. - // - // There is no *easy* way of comparing the fields - // further on, because they might have different types - // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and - // `.y` come from different structs). - // - // We could try to do some things here - e.g., count - // dereferences - but that's probably not a good - // idea, at least for now, so just give up and - // report a conflict. This is unsafe code anyway so - // the user could always use raw pointers. - debug!("borrow_conflicts_with_place: arbitrary -> conflict"); - return true; - } - Overlap::EqualOrDisjoint => { - // This is the recursive case - proceed to the next element. - } - Overlap::Disjoint => { - // We have proven the borrow disjoint - further - // projections will remain disjoint. - debug!("borrow_conflicts_with_place: disjoint"); - return false; - } - } - } else { - // Borrow path is longer than the access path. Examples: + // Borrow and access path both have more components. + // + // Examples: + // + // - borrow of `a.(...)`, access to `a.(...)` + // - borrow of `a.(...)`, access to `b.(...)` + // + // Here we only see the components we have checked so + // far (in our examples, just the first component). We + // check whether the components being borrowed vs + // accessed are disjoint (as in the second example, + // but not the first). + match place_projection_conflict( + tcx, + body, + borrow_base, + borrow_proj_base, + borrow_c, + access_c, + bias, + ) { + Overlap::Arbitrary => { + // We have encountered different fields of potentially + // the same union - the borrow now partially overlaps. // - // - borrow of `a.b.c`, access to `a.b` + // There is no *easy* way of comparing the fields + // further on, because they might have different types + // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and + // `.y` come from different structs). // - // Here, we know that the borrow can access a part of - // our place. This is a conflict if that is a part our - // access cares about. + // We could try to do some things here - e.g., count + // dereferences - but that's probably not a good + // idea, at least for now, so just give up and + // report a conflict. This is unsafe code anyway so + // the user could always use raw pointers. + debug!("borrow_conflicts_with_place: arbitrary -> conflict"); + return true; + } + Overlap::EqualOrDisjoint => { + // This is the recursive case - proceed to the next element. + } + Overlap::Disjoint => { + // We have proven the borrow disjoint - further + // projections will remain disjoint. + debug!("borrow_conflicts_with_place: disjoint"); + return false; + } + } + } + + if borrow_place.projection.len() > access_place.projection.len() { + for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate() + { + // Borrow path is longer than the access path. Examples: + // + // - borrow of `a.b.c`, access to `a.b` + // + // Here, we know that the borrow can access a part of + // our place. This is a conflict if that is a part our + // access cares about. - let base = &borrow_c.base; - let elem = &borrow_c.elem; - let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty; + let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; + let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty; - match (elem, &base_ty.sty, access) { - (_, _, Shallow(Some(ArtificialField::ArrayLength))) - | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { - // The array length is like additional fields on the - // type; it does not overlap any existing data there. - // Furthermore, if cannot actually be a prefix of any - // borrowed place (at least in MIR as it is currently.) - // - // e.g., a (mutable) borrow of `a[5]` while we read the - // array length of `a`. - debug!("borrow_conflicts_with_place: implicit field"); - return false; - } + match (elem, &base_ty.sty, access) { + (_, _, Shallow(Some(ArtificialField::ArrayLength))) + | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { + // The array length is like additional fields on the + // type; it does not overlap any existing data there. + // Furthermore, if cannot actually be a prefix of any + // borrowed place (at least in MIR as it is currently.) + // + // e.g., a (mutable) borrow of `a[5]` while we read the + // array length of `a`. + debug!("borrow_conflicts_with_place: implicit field"); + return false; + } - (ProjectionElem::Deref, _, Shallow(None)) => { - // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some - // prefix thereof - the shallow access can't touch anything behind - // the pointer. - debug!("borrow_conflicts_with_place: shallow access behind ptr"); - return false; - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { - // Shouldn't be tracked - bug!("Tracking borrow behind shared reference."); - } - (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => { - // Values behind a mutable reference are not access either by dropping a - // value, or by StorageDead - debug!("borrow_conflicts_with_place: drop access behind ptr"); - return false; - } + (ProjectionElem::Deref, _, Shallow(None)) => { + // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some + // prefix thereof - the shallow access can't touch anything behind + // the pointer. + debug!("borrow_conflicts_with_place: shallow access behind ptr"); + return false; + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { + // Shouldn't be tracked + bug!("Tracking borrow behind shared reference."); + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => { + // Values behind a mutable reference are not access either by dropping a + // value, or by StorageDead + debug!("borrow_conflicts_with_place: drop access behind ptr"); + return false; + } - (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { - // Drop can read/write arbitrary projections, so places - // conflict regardless of further projections. - if def.has_dtor(tcx) { - return true; - } + (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { + // Drop can read/write arbitrary projections, so places + // conflict regardless of further projections. + if def.has_dtor(tcx) { + return true; } + } - (ProjectionElem::Deref, _, Deep) - | (ProjectionElem::Deref, _, AccessDepth::Drop) - | (ProjectionElem::Field { .. }, _, _) - | (ProjectionElem::Index { .. }, _, _) - | (ProjectionElem::ConstantIndex { .. }, _, _) - | (ProjectionElem::Subslice { .. }, _, _) - | (ProjectionElem::Downcast { .. }, _, _) => { - // Recursive case. This can still be disjoint on a - // further iteration if this a shallow access and - // there's a deref later on, e.g., a borrow - // of `*x.y` while accessing `x`. - } + (ProjectionElem::Deref, _, Deep) + | (ProjectionElem::Deref, _, AccessDepth::Drop) + | (ProjectionElem::Field { .. }, _, _) + | (ProjectionElem::Index { .. }, _, _) + | (ProjectionElem::ConstantIndex { .. }, _, _) + | (ProjectionElem::Subslice { .. }, _, _) + | (ProjectionElem::Downcast { .. }, _, _) => { + // Recursive case. This can still be disjoint on a + // further iteration if this a shallow access and + // there's a deref later on, e.g., a borrow + // of `*x.y` while accessing `x`. } } - } else { - // Borrow path ran out but access path may not - // have. Examples: - // - // - borrow of `a.b`, access to `a.b.c` - // - borrow of `a.b`, access to `a.b` - // - // In the first example, where we didn't run out of - // access, the borrow can access all of our place, so we - // have a conflict. - // - // If the second example, where we did, then we still know - // that the borrow can access a *part* of our place that - // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() { - debug!("borrow_conflicts_with_place: shallow borrow"); - return false; - } else { - debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); - return true; - } } } + + // Borrow path ran out but access path may not + // have. Examples: + // + // - borrow of `a.b`, access to `a.b.c` + // - borrow of `a.b`, access to `a.b` + // + // In the first example, where we didn't run out of + // access, the borrow can access all of our place, so we + // have a conflict. + // + // If the second example, where we did, then we still know + // that the borrow can access a *part* of our place that + // our access cares about, so we still have a conflict. + if borrow_kind == BorrowKind::Shallow + && borrow_place.projection.len() < access_place.projection.len() + { + debug!("borrow_conflicts_with_place: shallow borrow"); + false + } else { + debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); + true + } } // Given that the bases of `elem1` and `elem2` are always either equal @@ -381,11 +386,12 @@ fn place_projection_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, pi1_base: &PlaceBase<'tcx>, - pi1: &Projection<'tcx>, - pi2: &Projection<'tcx>, + pi1_proj_base: &[PlaceElem<'tcx>], + pi1_elem: &PlaceElem<'tcx>, + pi2_elem: &PlaceElem<'tcx>, bias: PlaceConflictBias, ) -> Overlap { - match (&pi1.elem, &pi2.elem) { + match (pi1_elem, pi2_elem) { (ProjectionElem::Deref, ProjectionElem::Deref) => { // derefs (e.g., `*x` vs. `*x`) - recur. debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); @@ -397,7 +403,7 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty; + let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty; match ty.sty { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. @@ -493,7 +499,7 @@ fn place_projection_conflict<'tcx>( // element (like -1 in Python) and `min_length` the first. // Therefore, `min_length - offset_from_end` gives the minimal possible // offset from the beginning - if *offset_from_begin >= min_length - offset_from_end { + if *offset_from_begin >= *min_length - *offset_from_end { debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); Overlap::EqualOrDisjoint } else { @@ -538,8 +544,8 @@ fn place_projection_conflict<'tcx>( | (ProjectionElem::Subslice { .. }, _) | (ProjectionElem::Downcast(..), _) => bug!( "mismatched projections in place_element_conflict: {:?} and {:?}", - pi1, - pi2 + pi1_elem, + pi2_elem ), } } diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 4c6be23de28be..6adc693527f01 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -19,17 +19,9 @@ pub trait IsPrefixOf<'cx, 'tcx> { 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.projection == cursor { - return self.base == other.base; - } - - match cursor { - None => return false, - Some(proj) => cursor = &proj.base, - } - } + self.base == other.base + && self.projection.len() <= other.projection.len() + && self.projection == &other.projection[..self.projection.len()] } } @@ -81,112 +73,115 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // downcasts here, but may return a base of a downcast). 'cursor: loop { - let proj = match &cursor { + match &cursor { PlaceRef { base: PlaceBase::Local(_), - projection: None, + projection: [], } | // search yielded this leaf PlaceRef { base: PlaceBase::Static(_), - projection: None, + projection: [], } => { self.next = None; return Some(cursor); } PlaceRef { base: _, - projection: Some(proj), - } => proj, - }; - - match proj.elem { - ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { - // 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 = PlaceRef { - base: cursor.base, - projection: &proj.base, - }; - continue 'cursor; - } - ProjectionElem::Deref => { - // (handled below) - } - } - - assert_eq!(proj.elem, ProjectionElem::Deref); - - match self.kind { - PrefixSet::Shallow => { - // shallow prefixes are found by stripping away - // fields, but stop at *any* dereference. - // So we can just stop the traversal now. - self.next = None; - return Some(cursor); - } - PrefixSet::All => { - // all prefixes: just blindly enqueue the base - // of the projection. - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); - } - PrefixSet::Supporting => { - // fall through! - } - } - - assert_eq!(self.kind, PrefixSet::Supporting); - // supporting prefixes: strip away fields and - // derefs, except we stop at the deref of a shared - // reference. - - let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty; - match ty.sty { - ty::RawPtr(_) | - ty::Ref( - _, /*rgn*/ - _, /*ty*/ - hir::MutImmutable - ) => { - // don't continue traversing over derefs of raw pointers or shared borrows. - self.next = None; - return Some(cursor); - } - - ty::Ref( - _, /*rgn*/ - _, /*ty*/ - hir::MutMutable, - ) => { - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); - } - - ty::Adt(..) if ty.is_box() => { - self.next = Some(PlaceRef { - base: cursor.base, - projection: &proj.base, - }); - return Some(cursor); + projection: [.., elem], + } => { + let proj_base = &cursor.projection[..cursor.projection.len() - 1]; + + match elem { + ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { + // 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 = PlaceRef { + base: cursor.base, + projection: proj_base, + }; + continue 'cursor; + } + ProjectionElem::Deref => { + // (handled below) + } + } + + assert_eq!(*elem, ProjectionElem::Deref); + + match self.kind { + PrefixSet::Shallow => { + // shallow prefixes are found by stripping away + // fields, but stop at *any* dereference. + // So we can just stop the traversal now. + self.next = None; + return Some(cursor); + } + PrefixSet::All => { + // all prefixes: just blindly enqueue the base + // of the projection + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + PrefixSet::Supporting => { + // fall through! + } + } + + assert_eq!(self.kind, PrefixSet::Supporting); + // supporting prefixes: strip away fields and + // derefs, except we stop at the deref of a shared + // reference. + + let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty; + match ty.sty { + ty::RawPtr(_) | + ty::Ref( + _, /*rgn*/ + _, /*ty*/ + hir::MutImmutable + ) => { + // don't continue traversing over derefs of raw pointers or shared + // borrows. + self.next = None; + return Some(cursor); + } + + ty::Ref( + _, /*rgn*/ + _, /*ty*/ + hir::MutMutable, + ) => { + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + + ty::Adt(..) if ty.is_box() => { + self.next = Some(PlaceRef { + base: cursor.base, + projection: proj_base, + }); + return Some(cursor); + } + + _ => panic!("unknown type fed to Projection Deref."), + } } - - _ => panic!("unknown type fed to Projection Deref."), } } } diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 2587d14a73a8f..8bfd24a1e5915 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -120,7 +120,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc ); if let Place { base: PlaceBase::Local(user_local), - projection: None, + projection: box [], } = 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 98cf4bba1c75f..5af66faf6ee1e 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -129,7 +129,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { kind: StaticKind::Static, def_id: id, })), - projection: None, + projection: box [], }), ExprKind::PlaceTypeAscription { source, user_ty } => { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 1a186fa932ddb..1371bc5aee82f 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -500,14 +500,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mutability = match arg_place { Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } => this.local_decls[local].mutability, Place { base: PlaceBase::Local(local), - projection: Some(box Projection { - base: None, - elem: ProjectionElem::Deref, - }) + projection: box [ProjectionElem::Deref], } => { debug_assert!( this.local_decls[local].is_ref_for_guard(), @@ -517,21 +514,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Place { ref base, - projection: Some(box Projection { - base: ref base_proj, - elem: ProjectionElem::Field(upvar_index, _), - }), + projection: box [.., ProjectionElem::Field(upvar_index, _)], } | Place { ref base, - projection: Some(box Projection { - base: Some(box Projection { - base: ref base_proj, - elem: ProjectionElem::Field(upvar_index, _), - }), - elem: ProjectionElem::Deref, - }), + projection: box [.., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref], } => { + let base_proj = if let ProjectionElem::Deref = + arg_place.projection[arg_place.projection.len() - 1] + { + &arg_place.projection[..arg_place.projection.len() - 2] + } else { + &arg_place.projection[..arg_place.projection.len() - 1] + }; + let place = PlaceRef { base, projection: base_proj, diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 889861b856748..45f4a16853606 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -301,7 +301,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 destination.projection.is_some() { + if !destination.projection.is_empty() { 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 94323b15b696f..8c94723e3cc2e 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -942,13 +942,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for Binding { source, .. } in matched_candidates.iter().flat_map(|candidate| &candidate.bindings) { - let mut cursor = &source.projection; - while let Some(box Projection { base, elem }) = cursor { - cursor = base; + for (i, elem) in source.projection.iter().enumerate().rev() { + let proj_base = &source.projection[..i]; + if let ProjectionElem::Deref = elem { fake_borrows.insert(Place { base: source.base.clone(), - projection: cursor.clone(), + projection: proj_base.to_vec().into_boxed_slice(), }); break; } @@ -1295,18 +1295,18 @@ 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.projection; - while let Some(box Projection { base, elem }) = prefix_cursor { + for (i, elem) in place.projection.iter().enumerate().rev() { + let proj_base = &place.projection[..i]; + 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(PlaceRef { base: &place.base, - projection: base, + projection: proj_base, }); } - prefix_cursor = base; } all_fake_borrows.push(place.as_ref()); @@ -1493,7 +1493,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { BorrowKind::Shallow, Place { base: place.base.clone(), - projection: place.projection.clone(), + projection: place.projection.to_vec().into_boxed_slice(), }, ); self.cfg.push_assign( diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 7ab0bf7d66a64..647d7515fe98d 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -609,7 +609,7 @@ where unpack!(block = builder.in_breakable_scope( None, START_BLOCK, - Place::RETURN_PLACE, + Place::return_place(), |builder| { builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body(block, &arguments, arg_scope, &body.value) @@ -670,7 +670,7 @@ fn construct_const<'a, 'tcx>( let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr)); + unpack!(block = builder.into_expr(&Place::return_place(), block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let body = self.hir.mirror(ast_body); - self.into(&Place::RETURN_PLACE, block, body) + self.into(&Place::return_place(), block, body) } fn set_correct_source_scope_for_arg( diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a04c041ca9dc7..ee6d42de388d9 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -314,7 +314,7 @@ impl<'tcx> Scopes<'tcx> { match target { BreakableTarget::Return => { let scope = &self.breakable_scopes[0]; - if scope.break_destination != Place::RETURN_PLACE { + if scope.break_destination != Place::return_place() { span_bug!(span, "`return` in item with no return scope"); } (scope.break_block, scope.region_scope, Some(scope.break_destination.clone())) @@ -853,11 +853,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ if self.local_scope().is_none() => (), Operand::Copy(Place { base: PlaceBase::Local(cond_temp), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(cond_temp), - projection: None, + projection: box [], }) => { // Manually drop the condition on both branches. let top_scope = self.scopes.scopes.last_mut().unwrap(); diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index c071b3101fce3..672bbda7502fe 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -10,17 +10,12 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option - where F: FnMut(&mir::Projection<'tcx>) -> bool + where F: FnMut(&[mir::PlaceElem<'tcx>]) -> bool { 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.projection { - Some(ref proj) => { - if cond(proj) { - return Some(child_index) - } - } - _ => {} + if cond(&move_data.move_paths[child_index].place.projection) { + return Some(child_index) } next_child = move_data.move_paths[child_index].next_sibling; } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 2ea6c4ae10fdc..04674fb58cb9f 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -208,7 +208,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 place.projection.is_none() { + if place.projection.is_empty() { trans.kill_all(other_borrows_of_local); return; } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 81451c2500c47..1d99470d08b0c 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -94,72 +94,74 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// Maybe we should have separate "borrowck" and "moveck" modes. fn move_path_for(&mut self, place: &Place<'tcx>) -> Result> { debug!("lookup({:?})", place); - place.iterate(|place_base, place_projection| { - let mut base = match place_base { - PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local], - PlaceBase::Static(..) => { - return Err(MoveError::cannot_move_out_of(self.loc, Static)); - } - }; + let mut base = match place.base { + PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local], + PlaceBase::Static(..) => { + return Err(MoveError::cannot_move_out_of(self.loc, Static)); + } + }; - for proj in place_projection { - let body = self.builder.body; - let tcx = self.builder.tcx; - 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 { - base: place_base.clone(), - projection: Some(Box::new(proj.clone())), - }, + for (i, elem) in place.projection.iter().enumerate() { + let proj_base = &place.projection[..i]; + let body = self.builder.body; + let tcx = self.builder.tcx; + let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty; + match place_ty.sty { + ty::Ref(..) | ty::RawPtr(..) => { + let proj = &place.projection[..i+1]; + return Err(MoveError::cannot_move_out_of( + self.loc, + BorrowedContent { + target_place: Place { + base: place.base.clone(), + projection: proj.to_vec().into_boxed_slice(), }, - )); - } - ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { + }, + )); + } + ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfTypeWithDestructor { container_ty: place_ty }, + )); + } + // move out of union - always move the entire union + ty::Adt(adt, _) if adt.is_union() => { + return Err(MoveError::UnionMove { path: base }); + } + ty::Slice(_) => { + return Err(MoveError::cannot_move_out_of( + self.loc, + InteriorOfSliceOrArray { + ty: place_ty, + is_index: match elem { + ProjectionElem::Index(..) => true, + _ => false, + }, + }, + )); + } + ty::Array(..) => match elem { + ProjectionElem::Index(..) => { return Err(MoveError::cannot_move_out_of( self.loc, - InteriorOfTypeWithDestructor { container_ty: place_ty }, + InteriorOfSliceOrArray { ty: place_ty, is_index: true }, )); } - // move out of union - always move the entire union - ty::Adt(adt, _) if adt.is_union() => { - return Err(MoveError::UnionMove { path: base }); - } - ty::Slice(_) => { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { - ty: place_ty, - is_index: match proj.elem { - ProjectionElem::Index(..) => true, - _ => false, - }, - }, - )); + _ => { + // FIXME: still badly broken } - ty::Array(..) => match proj.elem { - ProjectionElem::Index(..) => { - return Err(MoveError::cannot_move_out_of( - self.loc, - InteriorOfSliceOrArray { ty: place_ty, is_index: true }, - )); - } - _ => { - // FIXME: still badly broken - } - }, - _ => {} - }; + }, + _ => {} + }; - base = match self - .builder - .data - .rev_lookup - .projections - .entry((base, proj.elem.lift())) + let proj = &place.projection[..i+1]; + base = match self + .builder + .data + .rev_lookup + .projections + .entry((base, elem.lift())) { Entry::Occupied(ent) => *ent.get(), Entry::Vacant(ent) => { @@ -169,18 +171,17 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { &mut self.builder.data.init_path_map, Some(base), Place { - base: place_base.clone(), - projection: Some(Box::new(proj.clone())), + base: place.base.clone(), + projection: proj.to_vec().into_boxed_slice(), }, ); ent.insert(path); path } }; - } + } - Ok(base) - }) + Ok(base) } fn create_move_path(&mut self, place: &Place<'tcx>) { @@ -355,7 +356,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | TerminatorKind::Unreachable => {} TerminatorKind::Return => { - self.gather_move(&Place::RETURN_PLACE); + self.gather_move(&Place::return_place()); } TerminatorKind::Assert { ref cond, .. } => { @@ -435,9 +436,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // 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 [.., ProjectionElem::Field(_, _)] = place.projection { + let proj_base = &place.projection[..place.projection.len() - 1]; if let ty::Adt(def, _) = Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 5028e9650918c..156c19c6363e5 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -245,23 +245,21 @@ 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_ref: PlaceRef<'_, '_>) -> 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), - }; - - for proj in place_projection { - if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) { - result = subpath; - } else { - return LookupResult::Parent(Some(result)); - } + pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult { + let mut result = match place.base { + PlaceBase::Local(local) => self.locals[*local], + PlaceBase::Static(..) => return LookupResult::Parent(None), + }; + + for elem in place.projection.iter() { + if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { + result = subpath; + } else { + return LookupResult::Parent(Some(result)); } + } - LookupResult::Exact(result) - }) + LookupResult::Exact(result) } pub fn find_local(&self, local: Local) -> MovePathIndex { @@ -329,7 +327,7 @@ 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), projection: None } = path.place { + if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place { return Some(l); } if let Some(parent) = path.parent { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index b5aab992e3adb..06b7206f4292c 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -472,39 +472,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // avoid allocations. pub(super) fn eval_place_to_op( &self, - mir_place: &mir::Place<'tcx>, + place: &mir::Place<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::PlaceBase; - mir_place.iterate(|place_base, place_projection| { - let mut op = match place_base { - PlaceBase::Local(mir::RETURN_PLACE) => - throw_unsup!(ReadFromReturnPointer), - PlaceBase::Local(local) => { - // Do not use the layout passed in as argument if the base we are looking at - // here is not the entire place. - // FIXME use place_projection.is_empty() when is available - let layout = if mir_place.projection.is_none() { - layout - } else { - None - }; - - self.access_local(self.frame(), *local, layout)? - } - PlaceBase::Static(place_static) => { - self.eval_static_to_mplace(place_static)?.into() - } - }; + let mut op = match &place.base { + PlaceBase::Local(mir::RETURN_PLACE) => + throw_unsup!(ReadFromReturnPointer), + PlaceBase::Local(local) => { + // Do not use the layout passed in as argument if the base we are looking at + // here is not the entire place. + // FIXME use place_projection.is_empty() when is available + let layout = if place.projection.is_empty() { + layout + } else { + None + }; - for proj in place_projection { - op = self.operand_projection(op, &proj.elem)? + self.access_local(self.frame(), *local, layout)? + } + PlaceBase::Static(place_static) => { + self.eval_static_to_mplace(&place_static)?.into() } + }; - trace!("eval_place_to_op: got {:?}", *op); - Ok(op) - }) + for elem in place.projection.iter() { + op = self.operand_projection(op, elem)? + } + + trace!("eval_place_to_op: got {:?}", *op); + Ok(op) } /// Evaluate the operand, returning a place where you can then find the data. diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f358bb00f4d12..1a28548618206 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -629,45 +629,43 @@ where /// place; for reading, a more efficient alternative is `eval_place_for_read`. pub fn eval_place( &mut self, - mir_place: &mir::Place<'tcx>, + place: &mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc::mir::PlaceBase; - mir_place.iterate(|place_base, place_projection| { - let mut place = match place_base { - PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { - Some(return_place) => { - // We use our layout to verify our assumption; caller will validate - // their layout on return. - PlaceTy { - place: *return_place, - layout: self.layout_of( - self.subst_from_frame_and_normalize_erasing_regions( - self.frame().body.return_ty() - ) - )?, - } + let mut place_ty = match &place.base { + PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { + Some(return_place) => { + // We use our layout to verify our assumption; caller will validate + // their layout on return. + PlaceTy { + place: *return_place, + layout: self.layout_of( + self.subst_from_frame_and_normalize_erasing_regions( + self.frame().body.return_ty() + ) + )?, } - None => throw_unsup!(InvalidNullPointerUsage), - }, - PlaceBase::Local(local) => PlaceTy { - // This works even for dead/uninitialized locals; we check further when writing - place: Place::Local { - frame: self.cur_frame(), - local: *local, - }, - layout: self.layout_of_local(self.frame(), *local, None)?, + } + None => throw_unsup!(InvalidNullPointerUsage), + }, + PlaceBase::Local(local) => PlaceTy { + // This works even for dead/uninitialized locals; we check further when writing + place: Place::Local { + frame: self.cur_frame(), + local: *local, }, - PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(), - }; + layout: self.layout_of_local(self.frame(), *local, None)?, + }, + PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(), + }; - for proj in place_projection { - place = self.place_projection(place, &proj.elem)? - } + for elem in place.projection.iter() { + place_ty = self.place_projection(place_ty, elem)? + } - self.dump_place(place.place); - Ok(place) - }) + self.dump_place(place_ty.place); + Ok(place_ty) } /// Write a scalar to a place diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 5de297923ce7b..8310ef02f9669 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -391,7 +391,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Don't forget to check the return type! if let Some(caller_ret) = dest { let callee_ret = self.eval_place( - &mir::Place::RETURN_PLACE + &mir::Place::return_place() )?; if !Self::check_argument_compat( rust_abi, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index aa83255bf62f4..9086ae844dd52 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -308,7 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span); - let dest = Place::RETURN_PLACE; + let dest = Place::return_place(); let src = Place::from(Local::new(1+0)).deref(); match self_ty.sty { @@ -415,7 +415,7 @@ impl CloneShimBuilder<'tcx> { let rcvr = Place::from(Local::new(1+0)).deref(); let ret_statement = self.make_statement( StatementKind::Assign( - Place::RETURN_PLACE, + Place::return_place(), box Rvalue::Use(Operand::Copy(rcvr)) ) ); @@ -773,7 +773,7 @@ fn build_call_shim<'tcx>( block(&mut blocks, statements, TerminatorKind::Call { func: callee, args, - destination: Some((Place::RETURN_PLACE, + destination: Some((Place::return_place(), BasicBlock::new(1))), cleanup: if let Adjustment::RefMut = rcvr_adjustment { Some(BasicBlock::new(3)) @@ -868,7 +868,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { debug!("build_ctor: variant_index={:?}", variant_index); let statements = expand_aggregate( - Place::RETURN_PLACE, + Place::return_place(), adt_def .variants[variant_index] .fields diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 0fd75cd57b2ac..466f6060827ec 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -17,12 +17,11 @@ pub struct AddRetag; fn is_stable( place: PlaceRef<'_, '_>, ) -> bool { - if let Some(proj) = &place.projection { - match proj.elem { + place.projection.iter().all(|elem| { + match elem { // Which place this evaluates to can change with any memory write, // so cannot assume this to be stable. - ProjectionElem::Deref => - false, + 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. @@ -31,15 +30,9 @@ fn is_stable( ProjectionElem::Field { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | - ProjectionElem::Downcast { .. } => - is_stable(PlaceRef { - base: place.base, - projection: &proj.base, - }), + ProjectionElem::Downcast { .. } => true, } - } else { - true - } + }) } /// Determine whether this type may be a reference (or box), and thus needs retagging. diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 539922c54d12d..f8af9b9fcbee0 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -200,127 +200,127 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, context: PlaceContext, _location: Location) { - place.iterate(|place_base, place_projections| { - match place_base { - PlaceBase::Local(..) => { - // Locals are safe. - } - PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { - bug!("unsafety checking should happen before promotion") - } - PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { - if self.tcx.is_mutable_static(*def_id) { - self.require_unsafe("use of mutable static", - "mutable statics can be mutated by multiple threads: aliasing \ - violations or data races will cause undefined behavior", - UnsafetyViolationKind::General); - } else if self.tcx.is_foreign_item(*def_id) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: InternedString::intern("use of extern static"), - details: InternedString::intern( - "extern statics are not controlled by the Rust type system: \ - invalid data, aliasing violations or data races will cause \ - undefined behavior"), - kind: UnsafetyViolationKind::ExternStatic(lint_root) - }], &[]); - } + match place.base { + PlaceBase::Local(..) => { + // Locals are safe. + } + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { + bug!("unsafety checking should happen before promotion") + } + PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { + if self.tcx.is_mutable_static(def_id) { + self.require_unsafe("use of mutable static", + "mutable statics can be mutated by multiple threads: aliasing \ + violations or data races will cause undefined behavior", + UnsafetyViolationKind::General); + } else if self.tcx.is_foreign_item(def_id) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: InternedString::intern("use of extern static"), + details: InternedString::intern( + "extern statics are not controlled by the Rust type system: \ + invalid data, aliasing violations or data races will cause \ + undefined behavior"), + kind: UnsafetyViolationKind::ExternStatic(lint_root) + }], &[]); } } + } - for proj in place_projections { - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, place) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: InternedString::intern("borrow of packed field"), - details: InternedString::intern( - "fields of packed structs might be misaligned: dereferencing a \ - misaligned pointer or even just creating a misaligned reference \ - is undefined behavior"), - kind: UnsafetyViolationKind::BorrowPacked(lint_root) - }], &[]); - } + for (i, elem) in place.projection.iter().enumerate() { + let proj_base = &place.projection[..i]; + + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.body, self.param_env, place) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: InternedString::intern("borrow of packed field"), + details: InternedString::intern( + "fields of packed structs might be misaligned: dereferencing a \ + misaligned pointer or even just creating a misaligned reference \ + is undefined behavior"), + kind: UnsafetyViolationKind::BorrowPacked(lint_root) + }], &[]); } - 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 - // * `&mut x.field` - // * `x.field = y;` - // * `&x.field` if `field`'s type has interior mutability - // because either of these would allow modifying the layout constrained field and - // insert values that violate the layout constraints. - if context.is_mutating_use() || is_borrow_of_interior_mut { - self.check_mut_borrowing_layout_constrained_field( - place, context.is_mutating_use(), - ); + } + 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 + // * `&mut x.field` + // * `x.field = y;` + // * `&x.field` if `field`'s type has interior mutability + // because either of these would allow modifying the layout constrained field and + // insert values that violate the layout constraints. + if context.is_mutating_use() || is_borrow_of_interior_mut { + self.check_mut_borrowing_layout_constrained_field( + place, context.is_mutating_use(), + ); + } + let old_source_info = self.source_info; + if let (PlaceBase::Local(local), []) = (&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; } - let old_source_info = self.source_info; - 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; - } + } + 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", + "raw pointers may be NULL, dangling or unaligned; they can violate \ + aliasing rules and cause data races: all of these are undefined \ + behavior", UnsafetyViolationKind::General) } - 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", - "raw pointers may be NULL, dangling or unaligned; they can violate \ - aliasing rules and cause data races: all of these are undefined \ - behavior", UnsafetyViolationKind::General) - } - ty::Adt(adt, _) => { - if adt.is_union() { - if context == PlaceContext::MutatingUse(MutatingUseContext::Store) || - context == PlaceContext::MutatingUse(MutatingUseContext::Drop) || - context == PlaceContext::MutatingUse( - MutatingUseContext::AsmOutput - ) - { - let elem_ty = match proj.elem { - ProjectionElem::Field(_, ty) => ty, - _ => span_bug!( - self.source_info.span, - "non-field projection {:?} from union?", - place) - }; - if !elem_ty.is_copy_modulo_regions( - self.tcx, - self.param_env, + ty::Adt(adt, _) => { + if adt.is_union() { + if context == PlaceContext::MutatingUse(MutatingUseContext::Store) || + context == PlaceContext::MutatingUse(MutatingUseContext::Drop) || + context == PlaceContext::MutatingUse( + MutatingUseContext::AsmOutput + ) + { + let elem_ty = match elem { + ProjectionElem::Field(_, ty) => ty, + _ => span_bug!( self.source_info.span, - ) { - self.require_unsafe( - "assignment to non-`Copy` union field", - "the previous content of the field will be dropped, which \ - causes undefined behavior if the field was not properly \ - initialized", UnsafetyViolationKind::General) - } else { - // write to non-move union, safe - } + "non-field projection {:?} from union?", + place) + }; + if !elem_ty.is_copy_modulo_regions( + self.tcx, + self.param_env, + self.source_info.span, + ) { + self.require_unsafe( + "assignment to non-`Copy` union field", + "the previous content of the field will be dropped, which \ + causes undefined behavior if the field was not properly \ + initialized", UnsafetyViolationKind::General) } else { - self.require_unsafe("access to union field", - "the field may not be properly initialized: using \ - uninitialized data will cause undefined behavior", - UnsafetyViolationKind::General) + // write to non-move union, safe } + } else { + self.require_unsafe("access to union field", + "the field may not be properly initialized: using \ + uninitialized data will cause undefined behavior", + UnsafetyViolationKind::General) } } - _ => {} } - self.source_info = old_source_info; + _ => {} } - }); + self.source_info = old_source_info; + } } } @@ -407,12 +407,13 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { place: &Place<'tcx>, is_mut_use: bool, ) { - let mut projection = &place.projection; - while let Some(proj) = projection { - match proj.elem { + for (i, elem) in place.projection.iter().enumerate().rev() { + let proj_base = &place.projection[..i]; + + match elem { ProjectionElem::Field(..) => { let ty = - Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx) + 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) { @@ -447,7 +448,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } _ => {} } - projection = &proj.base; } } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e4b186736e2a1..2e91561f2eee1 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -282,53 +282,53 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { trace!("eval_place(place={:?})", place); - place.iterate(|place_base, place_projection| { - let mut eval = match place_base { - PlaceBase::Local(loc) => self.get_const(*loc).clone()?, - PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => { - let generics = self.tcx.generics_of(self.source.def_id()); - if generics.requires_monomorphization(self.tcx) { - // FIXME: can't handle code with generics - return None; - } - let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); - let instance = Instance::new(self.source.def_id(), substs); - let cid = GlobalId { - instance, - promoted: Some(*promoted), - }; - let res = self.use_ecx(source_info, |this| { - this.ecx.const_eval_raw(cid) + let mut eval = match place.base { + PlaceBase::Local(loc) => self.get_const(loc).clone()?, + PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => { + let generics = self.tcx.generics_of(self.source.def_id()); + if generics.requires_monomorphization(self.tcx) { + // FIXME: can't handle code with generics + return None; + } + let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id()); + let instance = Instance::new(self.source.def_id(), substs); + let cid = GlobalId { + instance, + promoted: Some(promoted), + }; + let res = self.use_ecx(source_info, |this| { + this.ecx.const_eval_raw(cid) + })?; + trace!("evaluated promoted {:?} to {:?}", promoted, res); + res.into() + } + _ => return None, + }; + + for (i, elem) in place.projection.iter().enumerate() { + let proj_base = &place.projection[..i]; + + match elem { + ProjectionElem::Field(field, _) => { + trace!("field proj on {:?}", proj_base); + eval = self.use_ecx(source_info, |this| { + this.ecx.operand_field(eval, field.index() as u64) })?; - trace!("evaluated promoted {:?} to {:?}", promoted, res); - res.into() + }, + ProjectionElem::Deref => { + trace!("processing deref"); + eval = self.use_ecx(source_info, |this| { + this.ecx.deref_operand(eval) + })?.into(); } + // We could get more projections by using e.g., `operand_projection`, + // but we do not even have the stack frame set up properly so + // an `Index` projection would throw us off-track. _ => return None, - }; - - for proj in place_projection { - match proj.elem { - ProjectionElem::Field(field, _) => { - trace!("field proj on {:?}", proj.base); - eval = self.use_ecx(source_info, |this| { - this.ecx.operand_field(eval, field.index() as u64) - })?; - }, - ProjectionElem::Deref => { - trace!("processing deref"); - eval = self.use_ecx(source_info, |this| { - this.ecx.deref_operand(eval) - })?.into(); - } - // We could get more projections by using e.g., `operand_projection`, - // but we do not even have the stack frame set up properly so - // an `Index` projection would throw us off-track. - _ => return None, - } } + } - Some(eval) - }) + Some(eval) } fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { @@ -673,7 +673,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *place { trace!("checking whether {:?} can be stored to {:?}", value, local); if self.can_const_prop[local] { diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index f3a523a813413..20bdb4b03f081 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -96,7 +96,7 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { StatementKind::Assign( Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, box Rvalue::Use(ref operand) ) if local == dest_local => { @@ -150,21 +150,21 @@ fn eliminate_self_assignments( StatementKind::Assign( Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, box Rvalue::Use(Operand::Copy(Place { base: PlaceBase::Local(src_local), - projection: None, + projection: box [], })), ) | StatementKind::Assign( Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, box Rvalue::Use(Operand::Move(Place { base: PlaceBase::Local(src_local), - projection: None, + projection: box [], })), ) if local == dest_local && dest_local == src_local => {} _ => { @@ -194,7 +194,7 @@ impl<'tcx> Action<'tcx> { // The source must be a local. let src_local = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *src_place { local } else { @@ -351,11 +351,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { match *operand { Operand::Copy(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) | Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) 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 7a5c00c859629..47c7c2c5cb319 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -236,47 +236,37 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } fn field_subpath(&self, path: Self::Path, field: Field) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::Field(idx, _), .. - } => idx == field, - _ => false - } + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| match p { + [.., ProjectionElem::Field(idx, _)] => *idx == field, + _ => false, }) } fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, .. - } => offset == index, - &Projection { - elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, .. - } => size - offset == index, - _ => false + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| match p { + [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }] => { + *offset == index + } + [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }] => { + size - offset == index } + _ => false, }) } fn deref_subpath(&self, path: Self::Path) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { match p { - &Projection { elem: ProjectionElem::Deref, .. } => true, + [.., ProjectionElem::Deref] => true, _ => false } }) } fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - &Projection { - elem: ProjectionElem::Downcast(_, idx), .. - } => idx == variant, - _ => false - } + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| match p { + [.., ProjectionElem::Downcast(_, idx)] => *idx == variant, + _ => false }) } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index d87331195dd24..cf899c64406bc 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -107,10 +107,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { 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, - })), + projection: Box::new([ProjectionElem::Deref]), }); } else { self.super_place(place, context, location); @@ -137,10 +134,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { 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), - })), + projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]), }); } else { self.super_place(place, context, location); @@ -149,13 +143,12 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) { - 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; + + let mut new_projection = new_base.projection.to_vec(); + new_projection.append(&mut place.projection.to_vec()); + + place.projection = new_projection.into_boxed_slice(); } fn self_arg() -> Local { @@ -210,13 +203,12 @@ impl TransformVisitor<'tcx> { fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { let self_place = Place::from(self_arg()); let base = self_place.downcast_unnamed(variant_index); - let field = Projection { - base: base.projection, - elem: ProjectionElem::Field(Field::new(idx), ty), - }; + let mut projection = base.projection.to_vec(); + projection.push(ProjectionElem::Field(Field::new(idx), ty)); + Place { base: base.base, - projection: Some(Box::new(field)), + projection: projection.into_boxed_slice(), } } @@ -296,7 +288,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { // We must assign the value first in case it gets declared dead below data.statements.push(Statement { source_info, - kind: StatementKind::Assign(Place::RETURN_PLACE, + kind: StatementKind::Assign(Place::return_place(), box self.make_state(state_idx, v)), }); let state = if let Some(resume) = resume { // Yield @@ -848,7 +840,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut kind: TerminatorKind::Drop { location: Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, target, unwind diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index f31303c642faa..2b3c6d55f24dd 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -425,22 +425,20 @@ impl Inliner<'tcx> { // writes to `i`. To prevent this we need to create a temporary // borrow of the place and pass the destination as `*temp` instead. fn dest_needs_borrow(place: &Place<'_>) -> bool { - place.iterate(|place_base, place_projection| { - for proj in place_projection { - match proj.elem { - ProjectionElem::Deref | - ProjectionElem::Index(_) => return true, - _ => {} - } + for elem in place.projection.iter() { + match elem { + ProjectionElem::Deref | + ProjectionElem::Index(_) => return true, + _ => {} } + } - match place_base { - // Static variables need a borrow because the callee - // might modify the same static. - PlaceBase::Static(_) => true, - _ => false - } - }) + match place.base { + // Static variables need a borrow because the callee + // might modify the same static. + PlaceBase::Static(_) => true, + _ => false + } } let dest = if dest_needs_borrow(&destination.0) { @@ -591,7 +589,7 @@ impl Inliner<'tcx> { if let Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) = arg { if caller_body.local_kind(local) == LocalKind::Temp { // Reuse the operand if it's a temporary already @@ -660,7 +658,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { match self.destination { Place { base: PlaceBase::Local(l), - projection: None, + projection: box [], } => { *local = l; return; @@ -684,7 +682,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { match place { Place { base: PlaceBase::Local(RETURN_PLACE), - projection: None, + projection: box [], } => { // Return pointer; update the place itself *place = self.destination.clone(); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index abe41606e8079..b949e2f5ddd1d 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -43,12 +43,19 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { let new_place = match *rvalue { Rvalue::Ref(_, _, Place { ref mut base, - projection: Some(ref mut projection), - }) => Place { - // Replace with dummy - base: mem::replace(base, PlaceBase::Local(Local::new(0))), - projection: projection.base.take(), - }, + projection: ref mut projection @ box [.., _], + }) => { + let (proj_l, proj_r) = projection.split_at(projection.len() - 1); + + let place = Place { + // Replace with dummy + base: mem::replace(base, PlaceBase::Local(Local::new(0))), + projection: proj_l.to_vec().into_boxed_slice(), + }; + *projection = proj_r.to_vec().into_boxed_slice(); + + place + } _ => bug!("Detected `&*` but didn't find `&*`!"), }; *rvalue = Rvalue::Use(Operand::Copy(new_place)) @@ -83,12 +90,19 @@ 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 { - ref base, - projection: Some(ref projection), - }) = *rvalue { - if let ProjectionElem::Deref = projection.elem { - if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() { - self.optimizations.and_stars.insert(location); + base: _, + projection: box [.., elem], + }) = rvalue { + if *elem == ProjectionElem::Deref { + // FIXME remove this once we can use slices patterns + if let Rvalue::Ref(_, _, Place { + base, + projection, + }) = rvalue { + let proj_base = &projection[..projection.len() - 1]; + if Place::ty_from(base, proj_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 cdccdfea39943..0723a0c992e8e 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -318,7 +318,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { ty, def_id, }), - projection: None, + projection: box [], } }; let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); @@ -334,9 +334,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Operand::Move(Place { base: mem::replace( &mut place.base, - promoted_place(ty, span).base + promoted_place(ty, span).base, ), - projection: None, + projection: box [], }) } _ => bug!() @@ -422,7 +422,7 @@ pub fn promote_candidates<'tcx>( match body[block].statements[statement_index].kind { StatementKind::Assign(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }, _) => { if temps[local] == TempState::PromotedOut { // Already promoted. @@ -475,7 +475,7 @@ pub fn promote_candidates<'tcx>( match statement.kind { StatementKind::Assign(Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }, _) | StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { @@ -488,7 +488,7 @@ pub fn promote_candidates<'tcx>( match terminator.kind { TerminatorKind::Drop { location: Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }, target, .. } => { if promoted(index) { terminator.kind = TerminatorKind::Goto { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 32b49ee942300..27a46d3450317 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -187,26 +187,27 @@ trait Qualif { cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>, ) -> bool { - let proj = place.projection.as_ref().unwrap(); + let elem = &place.projection[place.projection.len() - 1]; + let proj_base = &place.projection[..place.projection.len() - 1]; let base_qualif = Self::in_place(cx, PlaceRef { base: place.base, - projection: &proj.base, + projection: proj_base, }); let qualif = base_qualif && Self::mask_for_ty( cx, - Place::ty_from(place.base, &proj.base, cx.body, cx.tcx) - .projection_ty(cx.tcx, &proj.elem) + Place::ty_from(place.base, proj_base, cx.body, cx.tcx) + .projection_ty(cx.tcx, elem) .ty, ); - match proj.elem { + match elem { ProjectionElem::Deref | ProjectionElem::Subslice { .. } | ProjectionElem::Field(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) => qualif, - ProjectionElem::Index(local) => qualif || Self::in_local(cx, local), + ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local), } } @@ -221,24 +222,24 @@ trait Qualif { match place { PlaceRef { base: PlaceBase::Local(local), - projection: None, + projection: [], } => Self::in_local(cx, *local), PlaceRef { base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }), - projection: None, + projection: [], } => bug!("qualifying already promoted MIR"), PlaceRef { base: PlaceBase::Static(static_), - projection: None, + projection: [], } => { Self::in_static(cx, static_) }, PlaceRef { base: _, - projection: Some(_), + projection: [.., _], } => Self::in_projection(cx, place), } } @@ -289,13 +290,16 @@ trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if let Some(ref proj) = place.projection { - if let ProjectionElem::Deref = proj.elem { - let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty; + if !place.projection.is_empty() { + let elem = &place.projection[place.projection.len() - 1]; + let proj_base = &place.projection[..place.projection.len() - 1]; + + if ProjectionElem::Deref == *elem { + 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, PlaceRef { base: &place.base, - projection: &proj.base, + projection: proj_base, }); } } @@ -453,9 +457,10 @@ impl Qualif for IsNotPromotable { cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>, ) -> bool { - let proj = place.projection.as_ref().unwrap(); + let elem = &place.projection[place.projection.len() - 1]; + let proj_base = &place.projection[..place.projection.len() - 1]; - match proj.elem { + match elem { ProjectionElem::Deref | ProjectionElem::Downcast(..) => return true, @@ -465,7 +470,7 @@ impl Qualif for IsNotPromotable { ProjectionElem::Field(..) => { if cx.mode == Mode::NonConstFn { - let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty; + let base_ty = Place::ty_from(place.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() { @@ -806,23 +811,18 @@ 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_projection = &place.projection; - while let Some(proj) = place_projection { - if proj.elem == ProjectionElem::Deref { - break; - } - place_projection = &proj.base; - } + let deref_proj = + place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref); debug!( "qualify_consts: promotion candidate: place={:?} {:?}", - place.base, place_projection + place.base, deref_proj ); // 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 (PlaceBase::Local(local), None) = (&place.base, place_projection) { + if let (PlaceBase::Local(local), None) = (&place.base, deref_proj) { if self.body.local_kind(*local) == LocalKind::Temp { debug!("qualify_consts: promotion candidate: local={:?}", local); // The borrowed place doesn't have `HasMutInterior` @@ -858,27 +858,29 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { _ => {}, } - let mut dest_projection = &dest.projection; + let mut dest_projection = &dest.projection[..]; let index = loop { match (&dest.base, dest_projection) { // We treat all locals equal in constants - (&PlaceBase::Local(index), None) => break index, + (&PlaceBase::Local(index), []) => break index, // projections are transparent for assignments // we qualify the entire destination at once, even if just a field would have // stricter qualification - (base, Some(proj)) => { + (base, proj @ [.., _]) => { + let proj_base = &proj[..proj.len() - 1]; + // Catch more errors in the destination. `visit_place` also checks various // projection rules like union field access and raw pointer deref let context = PlaceContext::MutatingUse(MutatingUseContext::Store); self.visit_place_base(base, context, location); self.visit_projection(base, proj, context, location); - dest_projection = &proj.base; + dest_projection = proj_base; }, (&PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. - }), None) => bug!("promoteds don't exist yet during promotion"), - (&PlaceBase::Static(box Static{ kind: _, .. }), None) => { + }), []) => bug!("promoteds don't exist yet during promotion"), + (&PlaceBase::Static(box Static{ kind: _, .. }), []) => { // 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 let context = PlaceContext::MutatingUse(MutatingUseContext::Store); @@ -986,7 +988,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { if let StatementKind::Assign(_, box Rvalue::Repeat( Operand::Move(Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }), _ )) = self.body[bb].statements[stmt_idx].kind { @@ -998,7 +1000,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { _, box Rvalue::Ref(_, _, Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }) ) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); @@ -1084,7 +1086,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { fn visit_projection( &mut self, place_base: &PlaceBase<'tcx>, - proj: &Projection<'tcx>, + proj: &[PlaceElem<'tcx>], context: PlaceContext, location: Location, ) { @@ -1093,62 +1095,68 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { 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 = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; - match self.mode { - Mode::NonConstFn => {}, - _ => { - if let ty::RawPtr(_) = base_ty.sty { - if !self.tcx.features().const_raw_ptr_deref { - emit_feature_err( - &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref, - self.span, GateIssue::Language, - &format!( - "dereferencing raw pointers in {}s is unstable", - self.mode, - ), - ); - } - } - } - } - } - ProjectionElem::ConstantIndex {..} | - ProjectionElem::Subslice {..} | - ProjectionElem::Field(..) | - ProjectionElem::Index(_) => { - 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 { - Mode::ConstFn => { - if !self.tcx.features().const_fn_union { + if !proj.is_empty() { + let elem = &proj[proj.len() - 1]; + let proj_base = &proj[..proj.len() - 1]; + + match elem { + ProjectionElem::Deref => { + if context.is_mutating_use() { + // `not_const` errors out in const contexts + self.not_const() + } + let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; + match self.mode { + Mode::NonConstFn => {}, + _ => { + if let ty::RawPtr(_) = base_ty.sty { + if !self.tcx.features().const_raw_ptr_deref { emit_feature_err( - &self.tcx.sess.parse_sess, sym::const_fn_union, + &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref, self.span, GateIssue::Language, - "unions in const fn are unstable", + &format!( + "dereferencing raw pointers in {}s is unstable", + self.mode, + ), ); } - }, + } + } + } + } - | Mode::NonConstFn - | Mode::Static - | Mode::StaticMut - | Mode::Const - => {}, + ProjectionElem::ConstantIndex {..} | + ProjectionElem::Subslice {..} | + ProjectionElem::Field(..) | + ProjectionElem::Index(_) => { + 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 { + Mode::ConstFn => { + if !self.tcx.features().const_fn_union { + emit_feature_err( + &self.tcx.sess.parse_sess, sym::const_fn_union, + self.span, GateIssue::Language, + "unions in const fn are unstable", + ); + } + }, + + | Mode::NonConstFn + | Mode::Static + | Mode::StaticMut + | Mode::Const + => {}, + } } } } - } - ProjectionElem::Downcast(..) => { - self.not_const() + ProjectionElem::Downcast(..) => { + self.not_const() + } } } } @@ -1162,7 +1170,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Mark the consumed locals to indicate later drops are noops. if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *place { self.cx.per_local[NeedsDrop].remove(local); } @@ -1179,11 +1187,12 @@ 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 Some(ref proj) = place.projection { - if let ProjectionElem::Deref = proj.elem { - let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty; + if let box [.., elem] = &place.projection { + if *elem == ProjectionElem::Deref { + let proj_base = &place.projection[..place.projection.len() - 1]; + 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); + reborrow_place = Some(proj_base); } } } @@ -1204,9 +1213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ), }; self.visit_place_base(&place.base, ctx, location); - if let Some(proj) = proj { - self.visit_projection(&place.base, proj, ctx, location); - } + self.visit_projection(&place.base, proj, ctx, location); } else { self.super_rvalue(rvalue, location); } @@ -1477,7 +1484,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // conservatively, that drop elaboration will do. let needs_drop = if let Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], } = *place { if NeedsDrop::in_local(self, local) { Some(self.body.local_decls[local].source_info.span) @@ -1727,7 +1734,7 @@ fn remove_drop_and_storage_dead_on_promoted_locals( TerminatorKind::Drop { location: Place { base: PlaceBase::Local(index), - projection: None, + projection: box [], }, target, .. diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 56093527aee24..cb2da1d5ff916 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -249,28 +249,26 @@ fn check_place( place: &Place<'tcx>, span: Span, ) -> McfResult { - place.iterate(|place_base, place_projection| { - for proj in place_projection { - match proj.elem { - ProjectionElem::Downcast(..) => { - return Err((span, "`match` or `if let` in `const fn` is unstable".into())); - } - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref - | ProjectionElem::Field(..) - | ProjectionElem::Index(_) => {} + for elem in place.projection.iter() { + match elem { + ProjectionElem::Downcast(..) => { + return Err((span, "`match` or `if let` in `const fn` is unstable".into())); } + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Deref + | ProjectionElem::Field(..) + | ProjectionElem::Index(_) => {} } + } - match place_base { - PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { - Err((span, "cannot access `static` items in const fn".into())) - } - PlaceBase::Local(_) - | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()), + match place.base { + PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { + Err((span, "cannot access `static` items in const fn".into())) } - }) + PlaceBase::Local(_) + | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()), + } } fn check_terminator( diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 73089a2106f6b..07669e2c0c986 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -43,7 +43,7 @@ impl RemoveNoopLandingPads { StatementKind::Assign(Place { base: PlaceBase::Local(_), - projection: None, + projection: box [], }, 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 1d3bf247387a7..208407bb9a5e0 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -120,11 +120,11 @@ fn each_block<'tcx, O>( let peek_arg_place = match args[0] { mir::Operand::Copy(ref place @ mir::Place { base: mir::PlaceBase::Local(_), - projection: None, + projection: box [], }) | mir::Operand::Move(ref place @ mir::Place { base: mir::PlaceBase::Local(_), - projection: None, + projection: box [], }) => Some(place), _ => None, }; diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 8199a252e78b0..318049a1ce0fe 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -61,14 +61,16 @@ 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 Some(ref proj) = src_place.projection { + if let box [.., elem] = &src_place.projection { + let proj_base = &src_place.projection[..src_place.projection.len() - 1]; + if let ProjectionElem::ConstantIndex{offset: _, min_length: _, - from_end: false} = proj.elem { + from_end: false} = elem { // no need to transformation } else { let place_ty = - Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).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.try_eval_usize(self.tcx, self.param_env) { assert!(size <= u32::max_value() as u64, @@ -78,7 +80,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { location, dst_place, &src_place.base, - proj, + &src_place.projection, item_ty, size as u32, ); @@ -97,73 +99,79 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { location: Location, dst_place: &Place<'tcx>, base: &PlaceBase<'tcx>, - proj: &Projection<'tcx>, + proj: &[PlaceElem<'tcx>], item_ty: &'tcx ty::TyS<'tcx>, size: u32) { - match proj.elem { - // uniforms statements like_10 = move _2[:-1]; - ProjectionElem::Subslice{from, to} => { - self.patch.make_nop(location); - let temps : Vec<_> = (from..(size-to)).map(|i| { - let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span); - self.patch.add_statement(location, StatementKind::StorageLive(temp)); + if !proj.is_empty() { + let elem = &proj[proj.len() - 1]; + let proj_base = &proj[..proj.len() - 1]; + + match elem { + // uniforms statements like_10 = move _2[:-1]; + ProjectionElem::Subslice{from, to} => { + self.patch.make_nop(location); + let temps : Vec<_> = (*from..(size-*to)).map(|i| { + let temp = + self.patch.new_temp(item_ty, self.body.source_info(location).span); + self.patch.add_statement(location, StatementKind::StorageLive(temp)); + + let mut projection = proj_base.to_vec(); + projection.push(ProjectionElem::ConstantIndex { + offset: i, + min_length: size, + from_end: false, + }); + self.patch.add_assign(location, + Place::from(temp), + Rvalue::Use( + Operand::Move( + Place { + base: base.clone(), + projection: projection.into_boxed_slice(), + } + ) + ) + ); + temp + }).collect(); + self.patch.add_assign( + location, + dst_place.clone(), + Rvalue::Aggregate( + box AggregateKind::Array(item_ty), + temps.iter().map( + |x| Operand::Move(Place::from(*x)) + ).collect() + ) + ); + for temp in temps { + self.patch.add_statement(location, StatementKind::StorageDead(temp)); + } + } + // uniforms statements like _11 = move _2[-1 of 1]; + ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { + self.patch.make_nop(location); + + let mut projection = proj_base.to_vec(); + projection.push(ProjectionElem::ConstantIndex { + offset: size - offset, + min_length: size, + from_end: false, + }); self.patch.add_assign(location, - Place::from(temp), + dst_place.clone(), Rvalue::Use( Operand::Move( Place { base: base.clone(), - projection: Some(box Projection { - base: proj.base.clone(), - elem: ProjectionElem::ConstantIndex { - offset: i, - min_length: size, - from_end: false, - } - }), + projection: projection.into_boxed_slice(), } ) ) ); - temp - }).collect(); - self.patch.add_assign( - location, - dst_place.clone(), - Rvalue::Aggregate( - box AggregateKind::Array(item_ty), - temps.iter().map( - |x| Operand::Move(Place::from(*x)) - ).collect() - ) - ); - for temp in temps { - self.patch.add_statement(location, StatementKind::StorageDead(temp)); } + _ => {} } - // uniforms statements like _11 = move _2[-1 of 1]; - ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => { - self.patch.make_nop(location); - self.patch.add_assign(location, - dst_place.clone(), - Rvalue::Use( - Operand::Move( - Place { - base: base.clone(), - projection: Some(box Projection { - base: proj.base.clone(), - elem: ProjectionElem::ConstantIndex { - offset: size - offset, - min_length: size, - from_end: false, - }, - }), - } - ) - ) - ); - } - _ => {} } } } @@ -202,7 +210,7 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { let items : Vec<_> = items.iter().map(|item| { if let Operand::Move(Place { base: PlaceBase::Local(local), - projection: None, + projection: box [], }) = item { let local_use = &visitor.locals_use[*local]; let opt_index_and_place = @@ -269,16 +277,17 @@ impl RestoreSubsliceArrayMoveOut { } patch.make_nop(candidate); let size = opt_size.unwrap() as u32; - patch.add_assign(candidate, - dst_place.clone(), - Rvalue::Use( - Operand::Move( - Place { - base: src_place.base.clone(), - projection: Some(box Projection { - base: src_place.projection.clone(), - elem: ProjectionElem::Subslice{ - from: min, to: size - max - 1}})}))); + + let mut projection = src_place.projection.to_vec(); + projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 }); + patch.add_assign( + candidate, + dst_place.clone(), + Rvalue::Use(Operand::Move(Place { + base: src_place.base.clone(), + projection: projection.into_boxed_slice(), + })), + ); } } @@ -291,21 +300,30 @@ impl RestoreSubsliceArrayMoveOut { if let StatementKind::Assign( Place { base: PlaceBase::Local(_), - projection: None, + projection: box [], }, box Rvalue::Use(Operand::Move(Place { - base, - projection: Some(box Projection { - base: proj_base, - elem: ProjectionElem::ConstantIndex { + base: _, + projection: box [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false - } - }), - }))) = &statement.kind { - return Some((*offset, PlaceRef { - base, - projection: proj_base, - })) + }], + })), + ) = &statement.kind { + // FIXME remove once we can use slices patterns + if let StatementKind::Assign( + _, + box Rvalue::Use(Operand::Move(Place { + base, + projection, + })), + ) = &statement.kind { + let proj_base = &projection[..projection.len() - 1]; + + 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 b8ef77da02e60..b4c97f9191732 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -38,14 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<' where L: HasLocalDecls<'tcx>, { - let mut place_projection = &place.projection; + for (i, elem) in place.projection.iter().enumerate().rev() { + let proj_base = &place.projection[..i]; - while let Some(proj) = place_projection { - match proj.elem { + match elem { // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = Place::ty_from(&place.base, &proj.base, 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 @@ -55,7 +55,6 @@ where } _ => {} } - place_projection = &proj.base; } false diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index f3e03e7f81daa..c60af70712d1b 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -586,10 +586,7 @@ where BorrowKind::Mut { allow_two_phase_borrow: false }, Place { base: PlaceBase::Local(cur), - projection: Some(Box::new(Projection { - base: None, - elem: ProjectionElem::Deref, - })), + projection: Box::new([ProjectionElem::Deref]), } ), Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one)) From 7efee8dd05b4a2439451b47de8df79c959faffcd Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 24 Aug 2019 16:04:32 -0700 Subject: [PATCH 02/11] Use rposition to find the position of an elem --- src/librustc_mir/build/matches/mod.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 8c94723e3cc2e..64368ab604645 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -942,16 +942,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for Binding { source, .. } in matched_candidates.iter().flat_map(|candidate| &candidate.bindings) { - for (i, elem) in source.projection.iter().enumerate().rev() { + if let Some(i) = + source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref) + { let proj_base = &source.projection[..i]; - if let ProjectionElem::Deref = elem { - fake_borrows.insert(Place { - base: source.base.clone(), - projection: proj_base.to_vec().into_boxed_slice(), - }); - break; - } + fake_borrows.insert(Place { + base: source.base.clone(), + projection: proj_base.to_vec().into_boxed_slice(), + }); } } } From b04e6c734451acc8b97657a906dda535874c82cf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 24 Aug 2019 19:49:08 -0400 Subject: [PATCH 03/11] Make move_path_children_matching closure take a PlaceElem instead of a slice --- .../dataflow/drop_flag_effects.rs | 11 ++++++---- src/librustc_mir/transform/elaborate_drops.rs | 21 ++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index 672bbda7502fe..444cc008ae785 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -10,14 +10,17 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option - where F: FnMut(&[mir::PlaceElem<'tcx>]) -> bool + where F: FnMut(&mir::PlaceElem<'tcx>) -> bool { let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { - if cond(&move_data.move_paths[child_index].place.projection) { - return Some(child_index) + let move_path_children = &move_data.move_paths[child_index]; + if let Some(elem) = move_path_children.place.projection.last() { + if cond(elem) { + return Some(child_index) + } } - next_child = move_data.move_paths[child_index].next_sibling; + next_child = move_path_children.next_sibling; } None diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 47c7c2c5cb319..de5978c3a3525 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -236,18 +236,18 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } fn field_subpath(&self, path: Self::Path, field: Field) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| match p { - [.., ProjectionElem::Field(idx, _)] => *idx == field, + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::Field(idx, _) => *idx == field, _ => false, }) } fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| match p { - [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }] => { + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => { *offset == index } - [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }] => { + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => { size - offset == index } _ => false, @@ -255,17 +255,14 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { } fn deref_subpath(&self, path: Self::Path) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { - match p { - [.., ProjectionElem::Deref] => true, - _ => false - } + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { + *e == ProjectionElem::Deref }) } fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { - dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| match p { - [.., ProjectionElem::Downcast(_, idx)] => *idx == variant, + dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { + ProjectionElem::Downcast(_, idx) => *idx == variant, _ => false }) } From e73d189e4e2ad55fcea595a14f9adea0960c65a1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 24 Aug 2019 20:53:20 -0400 Subject: [PATCH 04/11] Use slice patterns to match projection base --- src/librustc/mir/visit.rs | 5 +- src/librustc_codegen_ssa/mir/analyze.rs | 5 +- src/librustc_codegen_ssa/mir/place.rs | 8 +- .../borrow_check/error_reporting.rs | 10 +- src/librustc_mir/borrow_check/mod.rs | 4 +- src/librustc_mir/borrow_check/move_errors.rs | 7 +- .../borrow_check/mutability_errors.rs | 8 +- src/librustc_mir/borrow_check/prefixes.rs | 4 +- .../dataflow/move_paths/builder.rs | 3 +- src/librustc_mir/transform/instcombine.rs | 17 +--- src/librustc_mir/transform/qualify_consts.rs | 99 +++++++++---------- .../transform/uniform_array_move_out.rs | 15 +-- 12 files changed, 67 insertions(+), 118 deletions(-) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 36aa891aaf4aa..9f3df7cc58f60 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -720,12 +720,9 @@ macro_rules! make_mir_visitor { projection: & $($mutability)? [PlaceElem<'tcx>], context: PlaceContext, location: Location) { - if !projection.is_empty() { - let proj_len = projection.len(); - let proj_base = & $($mutability)? projection[..proj_len - 1]; + if let [proj_base @ .., elem] = projection { self.visit_projection(base, proj_base, context, location); - let elem = & $($mutability)? projection[proj_len - 1]; match elem { ProjectionElem::Field(_field, ty) => { self.visit_ty(ty, TyContext::Location(location)); diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 5449dbdc913b8..d192f2ffb6fba 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -105,10 +105,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { ) { let cx = self.fx.cx; - if let [.., elem] = place_ref.projection { - // FIXME(spastorino) include this in the pattern when stabilized - let proj_base = &place_ref.projection[..place_ref.projection.len() - 1]; - + if let [proj_base @ .., elem] = place_ref.projection { // Allow uses of projections that are ZSTs or from scalar fields. let is_consume = match context { PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index df90da7ee8fae..ef9fc36b0f173 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -514,10 +514,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }, mir::PlaceRef { base, - projection: [.., mir::ProjectionElem::Deref], + projection: [proj_base @ .., mir::ProjectionElem::Deref], } => { - let proj_base = &place_ref.projection[..place_ref.projection.len() - 1]; - // Load the pointer from its location. self.codegen_consume(bx, &mir::PlaceRef { base, @@ -526,10 +524,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::PlaceRef { base, - projection: [.., elem], + projection: [proj_base @ .., elem], } => { - let proj_base = &place_ref.projection[..place_ref.projection.len() - 1]; - // FIXME turn this recursion into iteration let cg_base = self.codegen_place(bx, &mir::PlaceRef { base, diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 1fbedc49ecf3f..aeee961d2d354 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -179,10 +179,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } PlaceRef { base, - projection: [.., elem], + projection: [proj_base @ .., elem], } => { - let proj_base = &place.projection[..place.projection.len() - 1]; - match elem { ProjectionElem::Deref => { let upvar_field_projection = @@ -363,11 +361,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.describe_field_from_ty(&static_.ty, field, None), PlaceRef { base, - projection: [.., elem], + projection: [proj_base @ .., elem], } => match elem { ProjectionElem::Deref => { - let proj_base = &place.projection[..place.projection.len() - 1]; - self.describe_field(PlaceRef { base, projection: proj_base, @@ -384,8 +380,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - let proj_base = &place.projection[..place.projection.len() - 1]; - self.describe_field(PlaceRef { base, projection: proj_base, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 041047bf7cdc8..2305984a017d0 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -2187,10 +2187,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } PlaceRef { base: _, - projection: [.., elem], + projection: [proj_base @ .., elem], } => { - let proj_base = &place.projection[..place.projection.len() - 1]; - match elem { ProjectionElem::Deref => { let base_ty = diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index d346a4cdfa21a..cdba1aafdacb0 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -305,11 +305,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); - let deref_base = match deref_target_place.projection { - box [.., ProjectionElem::Deref] => { - let proj_base = - &deref_target_place.projection[..deref_target_place.projection.len() - 1]; - + let deref_base = match &deref_target_place.projection { + box [proj_base @ .., ProjectionElem::Deref] => { PlaceRef { base: &deref_target_place.base, projection: proj_base, diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index dbc1d1700933f..12dc2cd1f91c3 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -65,10 +65,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: [.., ProjectionElem::Field(upvar_index, _)], + projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { - let proj_base = &the_place_err.projection[..the_place_err.projection.len() - 1]; - debug_assert!(is_closure_or_generator( Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty )); @@ -329,10 +327,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Also suggest adding mut for upvars PlaceRef { base, - projection: [.., ProjectionElem::Field(upvar_index, _)], + projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { - let proj_base = &the_place_err.projection[..the_place_err.projection.len() - 1]; - debug_assert!(is_closure_or_generator( Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty )); diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 6adc693527f01..819678dfaf255 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -88,10 +88,8 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { } PlaceRef { base: _, - projection: [.., elem], + projection: [proj_base @ .., elem], } => { - let proj_base = &cursor.projection[..cursor.projection.len() - 1]; - match elem { ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { // FIXME: add union handling diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 1d99470d08b0c..a4427287c4f80 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -436,8 +436,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // 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 [.., ProjectionElem::Field(_, _)] = place.projection { - let proj_base = &place.projection[..place.projection.len() - 1]; + if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection { if let ty::Adt(def, _) = Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty { diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index b949e2f5ddd1d..2b8e66e3dec1b 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -90,20 +90,11 @@ 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 { - base: _, - projection: box [.., elem], + base, + projection: box [proj_base @ .., ProjectionElem::Deref], }) = rvalue { - if *elem == ProjectionElem::Deref { - // FIXME remove this once we can use slices patterns - if let Rvalue::Ref(_, _, Place { - base, - projection, - }) = rvalue { - let proj_base = &projection[..projection.len() - 1]; - if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { - self.optimizations.and_stars.insert(location); - } - } + if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() { + self.optimizations.and_stars.insert(location); } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 27a46d3450317..e05b0c9662056 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -187,27 +187,28 @@ trait Qualif { cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>, ) -> bool { - let elem = &place.projection[place.projection.len() - 1]; - let proj_base = &place.projection[..place.projection.len() - 1]; + if let [proj_base @ .., elem] = place.projection { + let base_qualif = Self::in_place(cx, PlaceRef { + base: place.base, + projection: proj_base, + }); + let qualif = base_qualif && Self::mask_for_ty( + cx, + Place::ty_from(place.base, proj_base, cx.body, cx.tcx) + .projection_ty(cx.tcx, elem) + .ty, + ); + match elem { + ProjectionElem::Deref | + ProjectionElem::Subslice { .. } | + ProjectionElem::Field(..) | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Downcast(..) => qualif, - let base_qualif = Self::in_place(cx, PlaceRef { - base: place.base, - projection: proj_base, - }); - let qualif = base_qualif && Self::mask_for_ty( - cx, - Place::ty_from(place.base, proj_base, cx.body, cx.tcx) - .projection_ty(cx.tcx, elem) - .ty, - ); - match elem { - ProjectionElem::Deref | - ProjectionElem::Subslice { .. } | - ProjectionElem::Field(..) | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Downcast(..) => qualif, - - ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local), + ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local), + } + } else { + bug!("This should be called if projection is not empty"); } } @@ -290,10 +291,7 @@ trait Qualif { Rvalue::Ref(_, _, ref place) => { // Special-case reborrows to be more like a copy of the reference. - if !place.projection.is_empty() { - let elem = &place.projection[place.projection.len() - 1]; - let proj_base = &place.projection[..place.projection.len() - 1]; - + if let box [proj_base @ .., elem] = &place.projection { if ProjectionElem::Deref == *elem { let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.sty { @@ -457,31 +455,32 @@ impl Qualif for IsNotPromotable { cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>, ) -> bool { - let elem = &place.projection[place.projection.len() - 1]; - let proj_base = &place.projection[..place.projection.len() - 1]; - - match elem { - ProjectionElem::Deref | - ProjectionElem::Downcast(..) => return true, - - ProjectionElem::ConstantIndex {..} | - ProjectionElem::Subslice {..} | - ProjectionElem::Index(_) => {} + if let [proj_base @ .., elem] = place.projection { + match elem { + ProjectionElem::Deref | + ProjectionElem::Downcast(..) => return true, - ProjectionElem::Field(..) => { - if cx.mode == Mode::NonConstFn { - let base_ty = Place::ty_from(place.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() { - return true; + ProjectionElem::ConstantIndex {..} | + ProjectionElem::Subslice {..} | + ProjectionElem::Index(_) => {} + + ProjectionElem::Field(..) => { + if cx.mode == Mode::NonConstFn { + let base_ty = Place::ty_from(place.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() { + return true; + } } } } } - } - Self::in_projection_structurally(cx, place) + Self::in_projection_structurally(cx, place) + } else { + bug!("This should be called if projection is not empty"); + } } fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { @@ -866,14 +865,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // projections are transparent for assignments // we qualify the entire destination at once, even if just a field would have // stricter qualification - (base, proj @ [.., _]) => { - let proj_base = &proj[..proj.len() - 1]; - + (base, [proj_base @ .., _]) => { // Catch more errors in the destination. `visit_place` also checks various // projection rules like union field access and raw pointer deref let context = PlaceContext::MutatingUse(MutatingUseContext::Store); self.visit_place_base(base, context, location); - self.visit_projection(base, proj, context, location); + self.visit_projection(base, dest_projection, context, location); dest_projection = proj_base; }, (&PlaceBase::Static(box Static { @@ -1096,10 +1093,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ); self.super_projection(place_base, proj, context, location); - if !proj.is_empty() { - let elem = &proj[proj.len() - 1]; - let proj_base = &proj[..proj.len() - 1]; - + if let [proj_base @ .., elem] = proj { match elem { ProjectionElem::Deref => { if context.is_mutating_use() { @@ -1187,9 +1181,8 @@ 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 box [.., elem] = &place.projection { + if let box [proj_base @ .., elem] = &place.projection { if *elem == ProjectionElem::Deref { - let proj_base = &place.projection[..place.projection.len() - 1]; 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); diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 318049a1ce0fe..2f900f2638f48 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -61,9 +61,7 @@ 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 box [.., elem] = &src_place.projection { - let proj_base = &src_place.projection[..src_place.projection.len() - 1]; - + if let box [proj_base @ .., elem] = &src_place.projection { if let ProjectionElem::ConstantIndex{offset: _, min_length: _, from_end: false} = elem { @@ -102,10 +100,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { proj: &[PlaceElem<'tcx>], item_ty: &'tcx ty::TyS<'tcx>, size: u32) { - if !proj.is_empty() { - let elem = &proj[proj.len() - 1]; - let proj_base = &proj[..proj.len() - 1]; - + if let [proj_base @ .., elem] = proj { match elem { // uniforms statements like_10 = move _2[:-1]; ProjectionElem::Subslice{from, to} => { @@ -314,11 +309,9 @@ impl RestoreSubsliceArrayMoveOut { _, box Rvalue::Use(Operand::Move(Place { base, - projection, + projection: box [proj_base @ .., _], })), - ) = &statement.kind { - let proj_base = &projection[..projection.len() - 1]; - + ) = &statement.kind { return Some((*offset, PlaceRef { base, projection: proj_base, From 87420cd1bc9b032290e55e1569c6c45398eec929 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 11 Sep 2019 16:05:45 -0300 Subject: [PATCH 05/11] Make Place Boxed on Statement to reduce size from 64 bytes to 32 bytes --- src/librustc/mir/mod.rs | 20 +++--- src/librustc/mir/visit.rs | 9 ++- src/librustc_codegen_ssa/mir/statement.rs | 12 ++-- .../borrow_check/conflict_errors.rs | 14 ++-- .../borrow_check/error_reporting.rs | 11 ++- src/librustc_mir/borrow_check/mod.rs | 6 +- src/librustc_mir/borrow_check/move_errors.rs | 12 ++-- .../borrow_check/nll/explain_borrow/mod.rs | 6 +- .../borrow_check/nll/invalidation.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 4 +- src/librustc_mir/borrow_check/used_muts.rs | 2 +- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/expr/as_place.rs | 12 ++-- src/librustc_mir/build/matches/mod.rs | 26 ++++--- src/librustc_mir/dataflow/impls/borrows.rs | 4 +- .../dataflow/impls/storage_liveness.rs | 4 +- .../dataflow/move_paths/builder.rs | 2 +- src/librustc_mir/interpret/step.rs | 2 +- src/librustc_mir/shim.rs | 68 ++++++++++++------- src/librustc_mir/transform/add_retag.rs | 12 ++-- .../transform/cleanup_post_borrowck.rs | 2 +- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_mir/transform/copy_prop.rs | 48 +++++++------ src/librustc_mir/transform/deaggregator.rs | 6 +- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustc_mir/transform/generator.rs | 17 +++-- src/librustc_mir/transform/inline.rs | 4 +- src/librustc_mir/transform/promote_consts.rs | 21 +++--- src/librustc_mir/transform/qualify_consts.rs | 16 +++-- .../transform/qualify_min_const_fn.rs | 2 +- .../transform/remove_noop_landing_pads.rs | 4 +- src/librustc_mir/transform/rustc_peek.rs | 4 +- .../transform/uniform_array_move_out.rs | 36 +++++----- src/librustc_mir/util/aggregate.rs | 6 +- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_mir/util/patch.rs | 2 +- 36 files changed, 228 insertions(+), 176 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 602ce12c37d81..0ebc70750a6bb 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1547,7 +1547,7 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(Statement<'_>, 64); +static_assert_size!(Statement<'_>, 32); impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -1568,7 +1568,7 @@ impl Statement<'_> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Place. - Assign(Place<'tcx>, Box>), + Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), /// This represents all the reading that a pattern match may do /// (e.g., inspecting constants and discriminant values), and the @@ -1577,10 +1577,10 @@ pub enum StatementKind<'tcx> { /// /// Note that this also is emitted for regular `let` bindings to ensure that locals that are /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` - FakeRead(FakeReadCause, Place<'tcx>), + FakeRead(FakeReadCause, Box>), /// Write the discriminant for a variant to the enum Place. - SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx }, + SetDiscriminant { place: Box>, variant_index: VariantIdx }, /// Start a live range for the storage of the local. StorageLive(Local), @@ -1597,7 +1597,7 @@ pub enum StatementKind<'tcx> { /// by miri and only generated when "-Z mir-emit-retag" is passed. /// See /// for more details. - Retag(RetagKind, Place<'tcx>), + Retag(RetagKind, Box>), /// Encodes a user's type ascription. These need to be preserved /// intact so that NLL can respect them. For example: @@ -1611,7 +1611,7 @@ pub enum StatementKind<'tcx> { /// - `Contravariant` -- requires that `T_y :> T` /// - `Invariant` -- requires that `T_y == T` /// - `Bivariant` -- no effect - AscribeUserType(Place<'tcx>, ty::Variance, Box), + AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -1675,7 +1675,7 @@ impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; match self.kind { - Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), + Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv), FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), Retag(ref kind, ref place) => write!( fmt, @@ -1696,7 +1696,7 @@ impl Debug for Statement<'_> { InlineAsm(ref asm) => { write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) } - AscribeUserType(ref place, ref variance, ref c_ty) => { + AscribeUserType(box(ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } Nop => write!(fmt, "nop"), @@ -2998,14 +2998,14 @@ BraceStructTypeFoldableImpl! { EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { - (StatementKind::Assign)(a, b), + (StatementKind::Assign)(a), (StatementKind::FakeRead)(cause, place), (StatementKind::SetDiscriminant) { place, variant_index }, (StatementKind::StorageLive)(a), (StatementKind::StorageDead)(a), (StatementKind::InlineAsm)(a), (StatementKind::Retag)(kind, place), - (StatementKind::AscribeUserType)(a, v, b), + (StatementKind::AscribeUserType)(a, v), (StatementKind::Nop), } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 9f3df7cc58f60..1e3b9eb29c79d 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -344,7 +344,9 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); match kind { - StatementKind::Assign(place, rvalue) => { + StatementKind::Assign( + box(ref $($mutability)? place, ref $($mutability)? rvalue) + ) => { self.visit_assign(place, rvalue, location); } StatementKind::FakeRead(_, place) => { @@ -391,7 +393,10 @@ macro_rules! make_mir_visitor { StatementKind::Retag(kind, place) => { self.visit_retag(kind, place, location); } - StatementKind::AscribeUserType(place, variance, user_ty) => { + StatementKind::AscribeUserType( + box(ref $($mutability)? place, ref $($mutability)? user_ty), + variance + ) => { self.visit_ascribe_user_ty(place, variance, user_ty, location); } StatementKind::Nop => {} diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index b1bc57c2e90ec..dab7dfc041751 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -16,12 +16,12 @@ 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) => { + mir::StatementKind::Assign(box(ref place, ref rvalue)) => { if let mir::Place { base: mir::PlaceBase::Local(index), projection: box [], - } = *place { - match self.locals[index] { + } = place { + match self.locals[*index] { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) } @@ -30,7 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::Operand(None) => { let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); - if let Some(name) = self.mir.local_decls[index].name { + if let Some(name) = self.mir.local_decls[*index].name { match operand.val { OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { @@ -44,7 +44,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - self.locals[index] = LocalRef::Operand(Some(operand)); + self.locals[*index] = LocalRef::Operand(Some(operand)); bx } LocalRef::Operand(Some(op)) => { @@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_rvalue(bx, cg_dest, rvalue) } } - mir::StatementKind::SetDiscriminant{ref place, variant_index} => { + mir::StatementKind::SetDiscriminant{box ref place, variant_index} => { self.codegen_place(&mut bx, &place.as_ref()) .codegen_set_discr(&mut bx, variant_index); bx diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index a6f7c8f227c99..413f7e2e40635 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -1600,7 +1600,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "annotate_argument_and_return_for_borrow: location={:?}", location ); - if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..}) + if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..}) = &self.body[location.block].statements.get(location.statement_index) { debug!( @@ -1625,11 +1625,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { target, stmt ); if let StatementKind::Assign( - Place { - base: PlaceBase::Local(assigned_to), - projection: box [], - }, - box rvalue + box( + Place { + base: PlaceBase::Local(assigned_to), + projection: box [], + }, + rvalue + ) ) = &stmt.kind { debug!( "annotate_argument_and_return_for_borrow: assigned_to={:?} \ diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index aeee961d2d354..5bccd2835c980 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -41,7 +41,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut target = place.local_or_deref_local(); for stmt in &self.body[location.block].statements[location.statement_index..] { debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); - if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind { + if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind { debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); match from { Operand::Copy(ref place) | @@ -792,8 +792,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); if let StatementKind::Assign( - _, - box Rvalue::Aggregate(ref kind, ref places) + box(_, Rvalue::Aggregate(ref kind, ref places)) ) = stmt.kind { let (def_id, is_generator) = match kind { box AggregateKind::Closure(def_id, _) => (def_id, false), @@ -830,10 +829,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .get(location.statement_index) { Some(&Statement { - kind: StatementKind::Assign(Place { + kind: StatementKind::Assign(box(Place { base: PlaceBase::Local(local), projection: box [], - }, _), + }, _)), .. }) => local, _ => return OtherUse(use_span), @@ -846,7 +845,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for stmt in &self.body[location.block].statements[location.statement_index + 1..] { if let StatementKind::Assign( - _, box Rvalue::Aggregate(ref kind, ref places) + box(_, Rvalue::Aggregate(ref kind, ref places)) ) = stmt.kind { let (def_id, is_generator) = match kind { box AggregateKind::Closure(def_id, _) => (def_id, false), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 2305984a017d0..3b10d8f19668c 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -546,7 +546,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx self.check_activations(location, span, flow_state); match stmt.kind { - StatementKind::Assign(ref lhs, ref rhs) => { + StatementKind::Assign(box(ref lhs, ref rhs)) => { self.consume_rvalue( location, (rhs, span), @@ -561,7 +561,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx flow_state, ); } - StatementKind::FakeRead(_, ref place) => { + StatementKind::FakeRead(_, box ref place) => { // Read for match doesn't access any memory and is used to // assert that a place is safe and live. So we don't have to // do any checks here. @@ -1387,7 +1387,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let stmt = &bbd.statements[loc.statement_index]; debug!("temporary assigned in: stmt={:?}", stmt); - if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind { + if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind { propagate_closure_used_mut_place(self, source); } else { bug!("closures should only capture user variables \ diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index cdba1aafdacb0..aa732b0092a22 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -89,11 +89,13 @@ 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), - projection: box [], - }, - box Rvalue::Use(Operand::Move(move_from)), + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(Operand::Move(move_from)) + ) )) = self.body.basic_blocks()[location.block] .statements .get(location.statement_index) 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 ad68b4bc054bb..eae2f832ba791 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -541,10 +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 { + kind: StatementKind::Assign(box(Place { base: PlaceBase::Local(local), projection: box [], - }, _), + }, _)), .. }) = stmt { @@ -567,7 +567,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("was_captured_by_trait_object: stmt={:?}", stmt); // The only kind of statement that we care about is assignments... - if let StatementKind::Assign(place, box rvalue) = &stmt.kind { + if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind { let into = match place.local_or_deref_local() { Some(into) => into, None => { diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 71106af767064..1d429e3a6dee6 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -66,7 +66,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.check_activations(location); match statement.kind { - StatementKind::Assign(ref lhs, ref rhs) => { + StatementKind::Assign(box(ref lhs, ref rhs)) => { self.consume_rvalue( location, rhs, 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 599472958f4fc..10c038bc3336f 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1343,7 +1343,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("check_stmt: {:?}", stmt); let tcx = self.tcx(); match stmt.kind { - StatementKind::Assign(ref place, ref rv) => { + StatementKind::Assign(box(ref place, ref rv)) => { // Assignments to temporaries are not "interesting"; // they are not caused by the user, but rather artifacts // of lowering. Assignments to other sorts of places *are* interesting @@ -1450,7 +1450,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); }; } - StatementKind::AscribeUserType(ref place, variance, box ref projection) => { + StatementKind::AscribeUserType(box(ref place, ref projection), variance) => { let place_ty = place.ty(body, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 8bfd24a1e5915..695080dfe23d9 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -89,7 +89,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc _location: Location, ) { match &statement.kind { - StatementKind::Assign(into, _) => { + StatementKind::Assign(box(into, _)) => { if let PlaceBase::Local(local) = into.base { debug!( "visit_statement: statement={:?} local={:?} \ diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 778d1e71cedfc..3ed6b4ff34678 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -37,7 +37,7 @@ impl<'tcx> CFG<'tcx> { rvalue: Rvalue<'tcx>) { self.push(block, Statement { source_info, - kind: StatementKind::Assign(place.clone(), box rvalue) + kind: StatementKind::Assign(box(place.clone(), rvalue)) }); } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 5af66faf6ee1e..09b33c6654a9d 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -147,9 +147,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - place.clone(), + box( + place.clone(), + UserTypeProjection { base: annotation_index, projs: vec![], } + ), Variance::Invariant, - box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); @@ -174,9 +176,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - Place::from(temp.clone()), + box( + Place::from(temp.clone()), + UserTypeProjection { base: annotation_index, projs: vec![], }, + ), Variance::Invariant, - box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 64368ab604645..613044dba2902 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, kind: StatementKind::FakeRead( FakeReadCause::ForMatchedPlace, - scrutinee_place.clone(), + box(scrutinee_place.clone()), ), }); @@ -320,7 +320,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Statement { source_info, - kind: StatementKind::FakeRead(FakeReadCause::ForLet, place), + kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)), }, ); @@ -362,12 +362,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Statement { source_info: pattern_source_info, - kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()), + kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())), }, ); let ty_source_info = self.source_info(user_ty_span); - let user_ty = box pat_ascription_ty.user_ty( + let user_ty = pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, place.ty(&self.local_decls, self.hir.tcx()).ty, ty_source_info.span, @@ -377,7 +377,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info: ty_source_info, kind: StatementKind::AscribeUserType( - place, + box( + place, + user_ty, + ), // We always use invariant as the variance here. This is because the // variance field from the ascription refers to the variance to use // when applying the type to the value being matched, but this @@ -393,7 +396,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // contrast, is intended to be used to relate `T` to the type of // ``. ty::Variance::Invariant, - user_ty, ), }, ); @@ -1523,7 +1525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: guard_end, kind: StatementKind::FakeRead( FakeReadCause::ForMatchGuard, - Place::from(temp), + box(Place::from(temp)), ), }); } @@ -1573,7 +1575,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { post_guard_block, Statement { source_info: guard_end, - kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place), + kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)), }, ); } @@ -1606,7 +1608,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription.user_ty, ); - let user_ty = box ascription.user_ty.clone().user_ty( + let user_ty = ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, source_info.span @@ -1616,9 +1618,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - ascription.source.clone(), + box( + ascription.source.clone(), + user_ty, + ), ascription.variance, - user_ty, ), }, ); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 04674fb58cb9f..a86fcb30f4d36 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -268,8 +268,8 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { debug!("Borrows::statement_effect: stmt={:?}", stmt); match stmt.kind { - mir::StatementKind::Assign(ref lhs, ref rhs) => { - if let mir::Rvalue::Ref(_, _, ref place) = **rhs { + mir::StatementKind::Assign(box(ref lhs, ref rhs)) => { + if let mir::Rvalue::Ref(_, _, ref place) = *rhs { if place.ignore_borrow( self.tcx, self.body, diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 0e01701ea9e44..0f66b13fdc51a 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -119,8 +119,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { match stmt.kind { StatementKind::StorageLive(l) => sets.gen(l), StatementKind::StorageDead(l) => sets.kill(l), - StatementKind::Assign(ref place, _) - | StatementKind::SetDiscriminant { ref place, .. } => { + StatementKind::Assign(box(ref place, _)) + | StatementKind::SetDiscriminant { box ref place, .. } => { if let PlaceBase::Local(local) = place.base { sets.gen(local); } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index a4427287c4f80..698c50166270a 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -268,7 +268,7 @@ struct Gatherer<'b, 'a, 'tcx> { impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match stmt.kind { - StatementKind::Assign(ref place, ref rval) => { + StatementKind::Assign(box(ref place, ref rval)) => { self.create_move_path(place); if let RvalueInitializationState::Shallow = rval.initialization_state() { // Box starts out uninitialized - need to create a separate diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index ca4da451a1f2d..affca10bf5265 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -82,7 +82,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.memory.tcx.span = stmt.source_info.span; match stmt.kind { - Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?, + Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?, SetDiscriminant { ref place, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 9086ae844dd52..6daca5e261431 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -217,7 +217,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) // Function arguments should be retagged, and we make this one raw. body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()), + kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())), }); } let patch = { @@ -415,8 +415,10 @@ impl CloneShimBuilder<'tcx> { let rcvr = Place::from(Local::new(1+0)).deref(); let ret_statement = self.make_statement( StatementKind::Assign( - Place::return_place(), - box Rvalue::Use(Operand::Copy(rcvr)) + box( + Place::return_place(), + Rvalue::Use(Operand::Copy(rcvr)) + ) ) ); self.block(vec![ret_statement], TerminatorKind::Return, false); @@ -458,8 +460,10 @@ impl CloneShimBuilder<'tcx> { // `let ref_loc: &ty = &src;` let statement = self.make_statement( StatementKind::Assign( - ref_loc.clone(), - box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src) + box( + ref_loc.clone(), + Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src) + ) ) ); @@ -486,8 +490,10 @@ impl CloneShimBuilder<'tcx> { let cond = self.make_place(Mutability::Mut, tcx.types.bool); let compute_cond = self.make_statement( StatementKind::Assign( - cond.clone(), - box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)) + box( + cond.clone(), + Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)) + ) ) ); @@ -521,14 +527,18 @@ impl CloneShimBuilder<'tcx> { let inits = vec![ self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::Use(Operand::Constant(self.make_usize(0))) + box( + Place::from(beg), + Rvalue::Use(Operand::Constant(self.make_usize(0))) + ) ) ), self.make_statement( StatementKind::Assign( - end.clone(), - box Rvalue::Use(Operand::Constant(self.make_usize(len))) + box( + end.clone(), + Rvalue::Use(Operand::Constant(self.make_usize(len))) + ) ) ) ]; @@ -559,11 +569,13 @@ impl CloneShimBuilder<'tcx> { let statements = vec![ self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::BinaryOp( - BinOp::Add, - Operand::Copy(Place::from(beg)), - Operand::Constant(self.make_usize(1)) + box( + Place::from(beg), + Rvalue::BinaryOp( + BinOp::Add, + Operand::Copy(Place::from(beg)), + Operand::Constant(self.make_usize(1)) + ) ) ) ) @@ -582,8 +594,10 @@ impl CloneShimBuilder<'tcx> { let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span)); let init = self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::Use(Operand::Constant(self.make_usize(0))) + box( + Place::from(beg), + Rvalue::Use(Operand::Constant(self.make_usize(0))) + ) ) ); self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); @@ -609,11 +623,13 @@ impl CloneShimBuilder<'tcx> { // `goto #6;` let statement = self.make_statement( StatementKind::Assign( - Place::from(beg), - box Rvalue::BinaryOp( - BinOp::Add, - Operand::Copy(Place::from(beg)), - Operand::Constant(self.make_usize(1)) + box( + Place::from(beg), + Rvalue::BinaryOp( + BinOp::Add, + Operand::Copy(Place::from(beg)), + Operand::Constant(self.make_usize(1)) + ) ) ) ); @@ -727,8 +743,10 @@ fn build_call_shim<'tcx>( statements.push(Statement { source_info, kind: StatementKind::Assign( - Place::from(ref_rcvr), - box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l) + box( + Place::from(ref_rcvr), + Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l) + ) ) }); Operand::Move(Place::from(ref_rcvr)) diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 466f6060827ec..833c8b1646bb6 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -89,7 +89,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { basic_blocks[START_BLOCK].statements.splice(0..0, places.into_iter().map(|place| Statement { source_info, - kind: StatementKind::Retag(RetagKind::FnEntry, place), + kind: StatementKind::Retag(RetagKind::FnEntry, box(place)), }) ); } @@ -125,7 +125,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { for (source_info, dest_place, dest_block) in returns { basic_blocks[dest_block].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Default, dest_place), + kind: StatementKind::Retag(RetagKind::Default, box(dest_place)), }); } @@ -137,11 +137,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag { for i in (0..block_data.statements.len()).rev() { let (retag_kind, place) = match block_data.statements[i].kind { // If we are casting *from* a reference, we may have to retag-as-raw. - StatementKind::Assign(ref place, box Rvalue::Cast( + StatementKind::Assign(box(ref place, Rvalue::Cast( CastKind::Misc, ref src, dest_ty, - )) => { + ))) => { let src_ty = src.ty(&*local_decls, tcx); if src_ty.is_region_ptr() { // The only `Misc` casts on references are those creating raw pointers. @@ -155,7 +155,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { // Assignments of reference or ptr type are the ones where we may have // to update tags. This includes `x = &[mut] ...` and hence // we also retag after taking a reference! - StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => { + StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => { let kind = match rvalue { Rvalue::Ref(_, borrow_kind, _) if borrow_kind.allows_two_phase_borrow() @@ -173,7 +173,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert(i+1, Statement { source_info, - kind: StatementKind::Retag(retag_kind, place), + kind: StatementKind::Retag(retag_kind, box(place)), }); } } diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index ede1cb62f9451..ea173279aa073 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -39,7 +39,7 @@ impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements { location: Location) { match statement.kind { StatementKind::AscribeUserType(..) - | StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _)) + | StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _))) | StatementKind::FakeRead(..) => statement.make_nop(), _ => (), } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 2e91561f2eee1..614d5d2a4a2fb 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -665,7 +665,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { location: Location, ) { trace!("visit_statement: {:?}", statement); - if let StatementKind::Assign(ref place, ref mut rval) = statement.kind { + if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind { let place_ty: Ty<'tcx> = place .ty(&self.local_decls, self.tcx) .ty; diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 20bdb4b03f081..28f97f41b50cf 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -94,11 +94,13 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { // That use of the source must be an assignment. match statement.kind { StatementKind::Assign( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - box Rvalue::Use(ref operand) + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(ref operand) + ) ) if local == dest_local => { let maybe_action = match *operand { Operand::Copy(ref src_place) | @@ -148,24 +150,28 @@ 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), - projection: box [], - }, - box Rvalue::Use(Operand::Copy(Place { - base: PlaceBase::Local(src_local), - projection: box [], - })), + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(Operand::Copy(Place { + base: PlaceBase::Local(src_local), + projection: box [], + })), + ) ) | StatementKind::Assign( - Place { - base: PlaceBase::Local(local), - projection: box [], - }, - box Rvalue::Use(Operand::Move(Place { - base: PlaceBase::Local(src_local), - projection: box [], - })), + box( + Place { + base: PlaceBase::Local(local), + projection: box [], + }, + Rvalue::Use(Operand::Move(Place { + base: PlaceBase::Local(src_local), + projection: box [], + })), + ) ) if local == dest_local && dest_local == src_local => {} _ => { continue; diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 1fc7ce09aa647..c1224be6324e2 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -12,8 +12,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { for bb in basic_blocks { bb.expand_statements(|stmt| { // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). - if let StatementKind::Assign(_, ref rhs) = stmt.kind { - if let Rvalue::Aggregate(ref kind, _) = **rhs { + if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind { + if let Rvalue::Aggregate(ref kind, _) = *rhs { // FIXME(#48193) Deaggregate arrays when it's cheaper to do so. if let AggregateKind::Array(_) = **kind { return None; @@ -28,7 +28,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { let stmt = stmt.replace_nop(); let source_info = stmt.source_info; let (lhs, kind, operands) = match stmt.kind { - StatementKind::Assign(lhs, box rvalue) => { + StatementKind::Assign(box(lhs, rvalue)) => { match rvalue { Rvalue::Aggregate(kind, operands) => (lhs, kind, operands), _ => bug!() diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index de5978c3a3525..a9c66b3c8c6d1 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -452,7 +452,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); let assign = Statement { - kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())), + kind: StatementKind::Assign(box(location.clone(), Rvalue::Use(value.clone()))), source_info: terminator.source_info }; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index cf899c64406bc..0ce2db93c421d 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -217,7 +217,10 @@ impl TransformVisitor<'tcx> { let self_place = Place::from(self_arg()); Statement { source_info, - kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc }, + kind: StatementKind::SetDiscriminant { + place: box self_place, + variant_index: state_disc, + }, } } @@ -230,7 +233,7 @@ impl TransformVisitor<'tcx> { let self_place = Place::from(self_arg()); let assign = Statement { source_info: source_info(body), - kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)), + kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))), }; (assign, temp) } @@ -288,8 +291,12 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { // We must assign the value first in case it gets declared dead below data.statements.push(Statement { source_info, - kind: StatementKind::Assign(Place::return_place(), - box self.make_state(state_idx, v)), + kind: StatementKind::Assign( + box( + Place::return_place(), + self.make_state(state_idx, v) + ) + ), }); let state = if let Some(resume) = resume { // Yield let state = 3 + self.suspension_points.len(); @@ -929,7 +936,7 @@ fn create_generator_drop_shim<'tcx>( // Alias tracking must know we changed the type body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())), + kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())), }) } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 2b3c6d55f24dd..5ad026dc143c9 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -457,7 +457,7 @@ impl Inliner<'tcx> { let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(tmp.clone(), box dest) + kind: StatementKind::Assign(box(tmp.clone(), dest)) }; caller_body[callsite.bb] .statements.push(stmt); @@ -608,7 +608,7 @@ impl Inliner<'tcx> { let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(Place::from(arg_tmp), box arg), + kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)), }; caller_body[callsite.bb].statements.push(stmt); arg_tmp diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 0723a0c992e8e..7d1b96b8be170 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span, scope: OUTERMOST_SOURCE_SCOPE }, - kind: StatementKind::Assign(Place::from(dest), box rvalue) + kind: StatementKind::Assign(box(Place::from(dest), rvalue)) }); } @@ -222,10 +222,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // First, take the Rvalue or Call out of the source MIR, // or duplicate it, depending on keep_original. if loc.statement_index < no_stmts { - let (rvalue, source_info) = { + let (mut rvalue, source_info) = { let statement = &mut self.source[loc.block].statements[loc.statement_index]; let rhs = match statement.kind { - StatementKind::Assign(_, ref mut rhs) => rhs, + StatementKind::Assign(box(_, ref mut rhs)) => rhs, _ => { span_bug!(statement.source_info.span, "{:?} is not an assignment", statement); @@ -235,12 +235,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { (if self.keep_original { rhs.clone() } else { - let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]); + let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]); mem::replace(rhs, unit) }, statement.source_info) }; - let mut rvalue = *rvalue; self.visit_rvalue(&mut rvalue, loc); self.assign(new_temp, rvalue, source_info.span); } else { @@ -326,7 +325,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Candidate::Ref(loc) => { let ref mut statement = blocks[loc.block].statements[loc.statement_index]; match statement.kind { - StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => { + StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => { // Use the underlying local for this (necessarily interior) borrow. let ty = place.base.ty(local_decls).ty; let span = statement.source_info.span; @@ -345,7 +344,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Candidate::Repeat(loc) => { let ref mut statement = blocks[loc.block].statements[loc.statement_index]; match statement.kind { - StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => { + StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => { let ty = operand.ty(local_decls, self.tcx); let span = statement.source_info.span; mem::replace( @@ -420,10 +419,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 { + StatementKind::Assign(box(Place { base: PlaceBase::Local(local), projection: box [], - }, _) => { + }, _)) => { if temps[local] == TempState::PromotedOut { // Already promoted. continue; @@ -473,10 +472,10 @@ pub fn promote_candidates<'tcx>( for block in body.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { - StatementKind::Assign(Place { + StatementKind::Assign(box(Place { base: PlaceBase::Local(index), projection: box [], - }, _) | + }, _)) | StatementKind::StorageLive(index) | StatementKind::StorageDead(index) => { !promoted(index) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index e05b0c9662056..7cc1e634cf812 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -982,23 +982,25 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { for candidate in &self.promotion_candidates { match *candidate { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { - if let StatementKind::Assign(_, box Rvalue::Repeat( + if let StatementKind::Assign(box(_, Rvalue::Repeat( Operand::Move(Place { base: PlaceBase::Local(index), projection: box [], }), _ - )) = self.body[bb].statements[stmt_idx].kind { + ))) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); } } Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { if let StatementKind::Assign( - _, - box Rvalue::Ref(_, _, Place { - base: PlaceBase::Local(index), - projection: box [], - }) + box( + _, + Rvalue::Ref(_, _, Place { + base: PlaceBase::Local(index), + projection: box [], + }) + ) ) = self.body[bb].statements[stmt_idx].kind { promoted_temps.insert(index); } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index cb2da1d5ff916..80e020a9eb7e6 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -206,7 +206,7 @@ fn check_statement( ) -> McfResult { let span = statement.source_info.span; match &statement.kind { - StatementKind::Assign(place, rval) => { + StatementKind::Assign(box(place, rval)) => { check_place(place, span)?; check_rvalue(tcx, body, rval, span) } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 07669e2c0c986..70b11944e2fbc 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -41,10 +41,10 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(Place { + StatementKind::Assign(box(Place { base: PlaceBase::Local(_), projection: box [], - }, box Rvalue::Use(_)) => { + }, 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 208407bb9a5e0..68fa082d29407 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -150,7 +150,7 @@ fn each_block<'tcx, O>( for (j, stmt) in statements.iter().enumerate() { debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); let (place, rvalue) = match stmt.kind { - mir::StatementKind::Assign(ref place, ref rvalue) => { + mir::StatementKind::Assign(box(ref place, ref rvalue)) => { (place, rvalue) } mir::StatementKind::FakeRead(..) | @@ -166,7 +166,7 @@ fn each_block<'tcx, O>( }; if place == peek_arg_place { - if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue { + 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.as_ref()) { LookupResult::Exact(peek_mpi) => { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 2f900f2638f48..34ad5cb5dc787 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -200,8 +200,8 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { for candidate in &visitor.candidates { let statement = &body[candidate.block].statements[candidate.statement_index]; - if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind { - if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval { + if let StatementKind::Assign(box(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), @@ -293,24 +293,28 @@ impl RestoreSubsliceArrayMoveOut { if block.statements.len() > location.statement_index { let statement = &block.statements[location.statement_index]; if let StatementKind::Assign( - Place { - base: PlaceBase::Local(_), - projection: box [], - }, - box Rvalue::Use(Operand::Move(Place { - base: _, - projection: box [.., ProjectionElem::ConstantIndex { + box( + Place { + base: PlaceBase::Local(_), + projection: box [], + }, + Rvalue::Use(Operand::Move(Place { + base: _, + projection: box [.., ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false - }], - })), + }], + })), + ) ) = &statement.kind { // FIXME remove once we can use slices patterns if let StatementKind::Assign( - _, - box Rvalue::Use(Operand::Move(Place { - base, - projection: box [proj_base @ .., _], - })), + box( + _, + Rvalue::Use(Operand::Move(Place { + base, + projection: box [proj_base @ .., _], + })), + ) ) = &statement.kind { return Some((*offset, PlaceRef { base, diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs index 98e70671ab715..b3565d40b8e21 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/src/librustc_mir/util/aggregate.rs @@ -24,7 +24,7 @@ pub fn expand_aggregate<'tcx>( if adt_def.is_enum() { set_discriminant = Some(Statement { kind: StatementKind::SetDiscriminant { - place: lhs.clone(), + place: box(lhs.clone()), variant_index, }, source_info, @@ -39,7 +39,7 @@ pub fn expand_aggregate<'tcx>( let variant_index = VariantIdx::new(0); set_discriminant = Some(Statement { kind: StatementKind::SetDiscriminant { - place: lhs.clone(), + place: box(lhs.clone()), variant_index, }, source_info, @@ -70,7 +70,7 @@ pub fn expand_aggregate<'tcx>( }; Statement { source_info, - kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)), + kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))), } }).chain(set_discriminant) } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index c60af70712d1b..52ad97bbde1d7 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -978,7 +978,7 @@ where fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { Statement { source_info: self.source_info, - kind: StatementKind::Assign(lhs.clone(), box rhs) + kind: StatementKind::Assign(box(lhs.clone(), rhs)) } } } diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index eb457dacf8467..2ea9924af7f28 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -120,7 +120,7 @@ impl<'tcx> MirPatch<'tcx> { } pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { - self.add_statement(loc, StatementKind::Assign(place, box rv)); + self.add_statement(loc, StatementKind::Assign(box(place, rv))); } pub fn make_nop(&mut self, loc: Location) { From 9c0bbe09e9e8e621b8fad5c0eab9436ff478fd1d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 12 Sep 2019 15:25:33 -0300 Subject: [PATCH 06/11] Use fold --- src/librustc/mir/tcx.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index fbe25de0e762c..d776809839743 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -127,13 +127,10 @@ impl<'tcx> Place<'tcx> { ) -> PlaceTy<'tcx> where D: HasLocalDecls<'tcx> { - let mut place_ty = base.ty(local_decls); - - for elem in projection.iter() { - place_ty = place_ty.projection_ty(tcx, elem); - } - - place_ty + projection.iter().fold( + base.ty(local_decls), + |place_ty, elem| place_ty.projection_ty(tcx, elem) + ) } pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> From 232a4a28818d0056677d48932f15d8b0cd17ef32 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 12 Sep 2019 16:03:38 -0300 Subject: [PATCH 07/11] Destructure instead of using split_at --- src/librustc_mir/transform/instcombine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 2b8e66e3dec1b..da91a8daca368 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -45,7 +45,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { ref mut base, projection: ref mut projection @ box [.., _], }) => { - let (proj_l, proj_r) = projection.split_at(projection.len() - 1); + let [proj_l @ .., proj_r] = projection; let place = Place { // Replace with dummy From 07a706ecf594e9feca5c57ae5db9e237a080fadf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 12 Sep 2019 16:16:43 -0300 Subject: [PATCH 08/11] Avoid math and use patterns to grab projection base --- .../borrow_check/conflict_errors.rs | 5 +---- src/librustc_mir/borrow_check/mod.rs | 7 +++--- .../borrow_check/mutability_errors.rs | 9 ++------ src/librustc_mir/build/expr/as_rvalue.rs | 16 +++++--------- src/librustc_mir/transform/instcombine.rs | 22 ++++++++++--------- 5 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 413f7e2e40635..c901eb2905476 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -1520,10 +1520,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { [] => { StorageDeadOrDrop::LocalStorageDead } - [.., elem] => { - // FIXME(spastorino) revisit when we get rid of Box - let base = &place.projection[..place.projection.len() - 1]; - + [base @ .., elem] => { // FIXME(spastorino) make this iterate let base_access = self.classify_drop_access_kind(PlaceRef { base: place.base, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 3b10d8f19668c..5ef70461296c7 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -2324,14 +2324,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut place_projection = place_ref.projection; let mut by_ref = false; - if let [.., ProjectionElem::Deref] = place_projection { - place_projection = &place_projection[..place_projection.len() - 1]; + if let [proj_base @ .., ProjectionElem::Deref] = place_projection { + place_projection = proj_base; by_ref = true; } match place_projection { - [.., ProjectionElem::Field(field, _ty)] => { - let base = &place_projection[..place_projection.len() - 1]; + [base @ .., ProjectionElem::Field(field, _ty)] => { let tcx = self.infcx.tcx; let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty; diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 12dc2cd1f91c3..9b9dfc3023354 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -82,11 +82,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: [.., ProjectionElem::Deref], + projection: [base @ .., ProjectionElem::Deref], } => { - // FIXME(spastorino) once released use box [base @ .., ProjectionElem::Deref] - let base = &the_place_err.projection[..the_place_err.projection.len() - 1]; - if the_place_err.base == &PlaceBase::Local(Local::new(1)) && base.is_empty() && !self.upvars.is_empty() { @@ -243,14 +240,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // after the field access). PlaceRef { base, - projection: [.., + projection: [base_proj @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref, ], } => { - let base_proj = &the_place_err.projection[..the_place_err.projection.len() - 3]; - err.span_label(span, format!("cannot {ACT}", ACT = act)); if let Some((span, message)) = annotate_struct_field( diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 1371bc5aee82f..6692984524fec 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -514,20 +514,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Place { ref base, - projection: box [.., ProjectionElem::Field(upvar_index, _)], + projection: box [ref base_proj @ .., ProjectionElem::Field(upvar_index, _)], } | Place { ref base, - projection: box [.., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref], + projection: box [ + ref base_proj @ .., + ProjectionElem::Field(upvar_index, _), + ProjectionElem::Deref + ], } => { - let base_proj = if let ProjectionElem::Deref = - arg_place.projection[arg_place.projection.len() - 1] - { - &arg_place.projection[..arg_place.projection.len() - 2] - } else { - &arg_place.projection[..arg_place.projection.len() - 1] - }; - let place = PlaceRef { base, projection: base_proj, diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index da91a8daca368..0e04e63af4522 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -45,16 +45,18 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { ref mut base, projection: ref mut projection @ box [.., _], }) => { - let [proj_l @ .., proj_r] = projection; - - let place = Place { - // Replace with dummy - base: mem::replace(base, PlaceBase::Local(Local::new(0))), - projection: proj_l.to_vec().into_boxed_slice(), - }; - *projection = proj_r.to_vec().into_boxed_slice(); - - place + if let box [proj_l @ .., proj_r] = projection { + let place = Place { + // Replace with dummy + base: mem::replace(base, PlaceBase::Local(Local::new(0))), + projection: proj_l.to_vec().into_boxed_slice(), + }; + *projection = vec![proj_r.clone()].into_boxed_slice(); + + place + } else { + unreachable!(); + } } _ => bug!("Detected `&*` but didn't find `&*`!"), }; From 98edaead8249b936a29c53bffb095737643982dc Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 12 Sep 2019 16:20:20 -0300 Subject: [PATCH 09/11] Fix style in comments --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 10 +++++----- src/librustc_mir/borrow_check/prefixes.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) 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 10c038bc3336f..1d17bae559c59 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -488,16 +488,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { substs: tcx.mk_substs_trait(place_ty.ty, &[]), }; - // In order to have a Copy operand, the type T of the - // value must be Copy. Note that we prove that T: Copy, + // To have a `Copy` operand, the type `T` of the + // value must be `Copy`. Note that we prove that `T: Copy`, // rather than using the `is_copy_modulo_regions` // test. This is important because // `is_copy_modulo_regions` ignores the resulting region // obligations and assumes they pass. This can result in - // bounds from Copy impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use Copy before knowing + // bounds from `Copy` impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use `Copy` before knowing // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement Copy, then + // that if a value of some type could implement `Copy`, then // it must. self.cx.prove_trait_ref( trait_ref, diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 819678dfaf255..0a268ec134023 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -118,15 +118,15 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { match self.kind { PrefixSet::Shallow => { - // shallow prefixes are found by stripping away + // Shallow prefixes are found by stripping away // fields, but stop at *any* dereference. // So we can just stop the traversal now. self.next = None; return Some(cursor); } PrefixSet::All => { - // all prefixes: just blindly enqueue the base - // of the projection + // All prefixes: just blindly enqueue the base + // of the projection. self.next = Some(PlaceRef { base: cursor.base, projection: proj_base, @@ -134,12 +134,12 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { return Some(cursor); } PrefixSet::Supporting => { - // fall through! + // Fall through! } } assert_eq!(self.kind, PrefixSet::Supporting); - // supporting prefixes: strip away fields and + // Supporting prefixes: strip away fields and // derefs, except we stop at the deref of a shared // reference. From 6ffc20f6a38ee78b1b496182281e6f5c8ddbaa02 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 12 Sep 2019 16:21:47 -0300 Subject: [PATCH 10/11] Use if let here --- src/librustc_mir/borrow_check/place_ext.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 50067345c65ee..411fa5b596765 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -57,7 +57,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { if *elem == ProjectionElem::Deref { let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty; - match ty.sty { + if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = ty.sty { // For both derefs of raw pointers and `&T` // references, the original path is `Copy` and // therefore not significant. In particular, @@ -68,8 +68,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { // original path into a new variable and // borrowed *that* one, leaving the original // path unborrowed. - ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true, - _ => {} + return true; } } } From 28db2c9e953f4e1e0f1511193c90b84f4d170d1a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 12 Sep 2019 17:33:38 -0300 Subject: [PATCH 11/11] Make all projection base names be proj_base --- src/librustc_mir/borrow_check/conflict_errors.rs | 14 +++++++------- src/librustc_mir/borrow_check/mutability_errors.rs | 12 ++++++------ src/librustc_mir/build/expr/as_rvalue.rs | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index c901eb2905476..4b4516d6bf290 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -615,13 +615,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } = first_borrowed_place; for (i, elem) in projection.iter().enumerate().rev() { - let base_proj = &projection[..i]; + let proj_base = &projection[..i]; match elem { - ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => { + ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => { return Some((PlaceRef { base: base, - projection: base_proj, + projection: proj_base, }, field)); }, _ => {}, @@ -1520,18 +1520,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { [] => { StorageDeadOrDrop::LocalStorageDead } - [base @ .., elem] => { + [proj_base @ .., elem] => { // FIXME(spastorino) make this iterate let base_access = self.classify_drop_access_kind(PlaceRef { base: place.base, - projection: base, + projection: proj_base, }); match elem { ProjectionElem::Deref => match base_access { StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(), + Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1539,7 +1539,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty; + let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty; match base_ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 9b9dfc3023354..14b76d97b3e57 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -82,10 +82,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: _, - projection: [base @ .., ProjectionElem::Deref], + projection: [proj_base @ .., ProjectionElem::Deref], } => { if the_place_err.base == &PlaceBase::Local(Local::new(1)) && - base.is_empty() && + proj_base.is_empty() && !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); @@ -106,7 +106,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ", as `Fn` closures cannot mutate their captured variables".to_string() } } else if { - if let (PlaceBase::Local(local), []) = (&the_place_err.base, base) { + if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) { self.body.local_decls[*local].is_ref_for_guard() } else { false @@ -117,7 +117,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { let source = self.borrowed_content_source(PlaceRef { base: the_place_err.base, - projection: base, + projection: proj_base, }); let pointer_type = source.describe_for_immutable_place(); opt_source = Some(source); @@ -240,7 +240,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // after the field access). PlaceRef { base, - projection: [base_proj @ .., + projection: [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref, @@ -250,7 +250,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - Place::ty_from(base, base_proj, self.body, self.infcx.tcx).ty, + Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6692984524fec..7dfe98cbebfc2 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -514,19 +514,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Place { ref base, - projection: box [ref base_proj @ .., ProjectionElem::Field(upvar_index, _)], + projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], } | Place { ref base, projection: box [ - ref base_proj @ .., + ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref ], } => { let place = PlaceRef { base, - projection: base_proj, + projection: proj_base, }; // Not projected from the implicit `self` in a closure.