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;
// `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
pub base: PlaceBase<'tcx>,
/// projection out of a place (access a field, deref a pointer, etc)
- pub projection: Option<Box<Projection<'tcx>>>,
+ pub projection: Box<[PlaceElem<'tcx>]>,
}
#[derive(
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<Box<Projection<'tcx>>>,
- pub elem: PlaceElem<'tcx>,
-}
-
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlaceRef<'a, 'tcx> {
pub base: &'a PlaceBase<'tcx>,
- pub projection: &'a Option<Box<Projection<'tcx>>>,
+ 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))
}
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(),
}
}
/// 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
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<R>(
- &self,
- op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
- ) -> R {
- Place::iterate_over(&self.base, &self.projection, op)
- }
-
- pub fn iterate_over<R>(
- place_base: &PlaceBase<'tcx>,
- place_projection: &Option<Box<Projection<'tcx>>>,
- op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
- ) -> R {
- fn iterate_over2<'tcx, R>(
- place_base: &PlaceBase<'tcx>,
- place_projection: &Option<Box<Projection<'tcx>>>,
- 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,
fn from(local: Local) -> Self {
Place {
base: local.into(),
- projection: None,
+ projection: Box::new([]),
}
}
}
}
impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
- pub fn iterate<R>(
- &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.
//
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<Self::Item> {
- 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(())
}
}
}
}
-impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&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<Vs: TypeVisitor<'tcx>>(&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,
+ }
}
}
impl<'tcx> Place<'tcx> {
pub fn ty_from<D>(
base: &PlaceBase<'tcx>,
- projection: &Option<Box<Projection<'tcx>>>,
+ 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<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
}
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,
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 {
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,
}
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(_, _) => {
+ }
}
}
}
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(libc)]
+#![feature(slice_patterns)]
#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
#![feature(in_band_lifetimes)]
) {
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) |
};
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 {
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`,
self.process_place(
&mir::PlaceRef {
base: place_ref.base,
- projection: &proj.base,
+ projection: proj_base,
},
context,
location,
}
// 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
// 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 {
}
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);
}
}
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;
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 {
ty,
def_id: _,
}),
- projection: None,
+ projection: box [],
}
) |
mir::Operand::Move(
ty,
def_id: _,
}),
- projection: None,
+ projection: box [],
}
) => {
let param_env = ty::ParamEnv::reveal_all();
}
let dest = if let mir::Place {
base: mir::PlaceBase::Local(index),
- projection: None,
+ projection: box [],
} = *dest {
match self.locals[index] {
LocalRef::Place(dest) => dest,
) {
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),
) -> Option<OperandRef<'tcx, Bx::Value>> {
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(
let result = match &place_ref {
mir::PlaceRef {
base: mir::PlaceBase::Local(index),
- projection: None,
+ projection: [],
} => {
match self.locals[*index] {
LocalRef::Place(place) => {
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));
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.
},
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,
}
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();
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
subslice
}
mir::ProjectionElem::Downcast(_, v) => {
- cg_base.project_downcast(bx, v)
+ cg_base.project_downcast(bx, *v)
}
}
}
// 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 {
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) => {
// so extract `temp`.
let temp = if let &mir::Place {
base: mir::PlaceBase::Local(temp),
- projection: None,
+ projection: box [],
} = assigned_place {
temp
} else {
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;
}
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)
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 {
projection: base_proj,
}, field));
},
- _ => current = base_proj,
+ _ => {},
}
}
None
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
}
}
}
-
- current = proj_base;
}
None
})
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,
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!(
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) =
let local_kind = match borrow.borrowed_place {
Place {
base: PlaceBase::Local(local),
- projection: None,
+ projection: box [],
} => {
match self.body.local_kind(local) {
LocalKind::ReturnPointer
.unwrap();
let local = if let PlaceRef {
base: PlaceBase::Local(local),
- projection: None,
+ projection: [],
} = root_place {
local
} else {
) {
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]))
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,
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,
};
if let StatementKind::Assign(
Place {
base: PlaceBase::Local(assigned_to),
- projection: None,
+ projection: box [],
},
box rvalue
) = &stmt.kind {
if let TerminatorKind::Call {
destination: Some((Place {
base: PlaceBase::Local(assigned_to),
- projection: None,
+ projection: box [],
}, _)),
args,
..
match place {
PlaceRef {
base: PlaceBase::Local(local),
- projection: None,
+ projection: [],
} => {
self.append_local_to_string(*local, buf)?;
}
kind: StaticKind::Promoted(..),
..
}),
- projection: None,
+ projection: [],
} => {
buf.push_str("promoted");
}
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);
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,
self.append_place_to_string(
PlaceRef {
base,
- projection: &proj.base,
+ projection: proj_base,
},
buf,
autoderef,
self.append_place_to_string(
PlaceRef {
base,
- projection: &proj.base,
+ projection: proj_base,
},
buf,
autoderef,
self.append_place_to_string(
PlaceRef {
base,
- projection: &proj.base,
+ projection: proj_base,
},
buf,
autoderef,
} 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,
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("]");
self.append_place_to_string(
PlaceRef {
base,
- projection: &proj.base,
+ projection: proj_base,
},
buf,
autoderef,
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)
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)
}
},
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));
Some(&Statement {
kind: StatementKind::Assign(Place {
base: PlaceBase::Local(local),
- projection: None,
+ projection: box [],
}, _),
..
}) => local,
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};
struct RootPlace<'d, 'tcx> {
place_base: &'d PlaceBase<'tcx>,
- place_projection: &'d Option<Box<Projection<'tcx>>>,
+ place_projection: &'d [PlaceElem<'tcx>],
is_local_mutation_allowed: LocalMutationIsAllowed,
}
// 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
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);
}
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.
//
// 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(..),
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.
// 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)
}
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
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 {
}
}
}
-
- place_projection = base;
}
fn check_parent_of_field<'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
} => {}
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 {
}
RootPlace {
place_base: PlaceBase::Static(..),
- place_projection: None,
+ place_projection: [],
is_local_mutation_allowed: _,
} => {}
}
match place {
PlaceRef {
base: PlaceBase::Local(local),
- projection: None,
+ projection: [],
} => {
let local = &self.body.local_decls[*local];
match local.mutability {
kind: StaticKind::Promoted(..),
..
}),
- projection: None,
+ projection: [],
} =>
Ok(RootPlace {
place_base: place.base,
def_id,
..
}),
- projection: None,
+ projection: [],
} => {
if !self.infcx.tcx.is_mutable_static(*def_id) {
Err(place)
}
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 {
self.is_mutable(PlaceRef {
base: place.base,
- projection: &proj.base,
+ projection: proj_base,
}, mode)
}
}
_ 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
// ```
let _ = self.is_mutable(PlaceRef {
base: place.base,
- projection: &proj.base,
+ projection: proj_base,
}, is_local_mutation_allowed)?;
Ok(RootPlace {
place_base: place.base,
} else {
self.is_mutable(PlaceRef {
base: place.base,
- projection: &proj.base,
+ projection: proj_base,
}, is_local_mutation_allowed)
}
}
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) {
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]
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!(
.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() {
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;
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 {
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());
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());
", 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
kind: StaticKind::Promoted(..),
..
}),
- projection: None,
+ projection: [],
} => unreachable!(),
PlaceRef {
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();
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."),
}
// 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(
// 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(
// 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`,
// 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));
// 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 ")
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
// 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];
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() =>
PlaceRef {
base: _,
- projection: Some(box Projection {
- base: _,
- elem: ProjectionElem::Deref,
- }),
+ projection: [.., ProjectionElem::Deref],
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
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};
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={:?}",
Place {
base: PlaceBase::Local(local),
- projection: Some(_),
+ projection: box [.., _],
} => {
// Kill conflicting borrows of the innermost local.
debug!(
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
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() {
let mut target = if let Some(&Statement {
kind: StatementKind::Assign(Place {
base: PlaceBase::Local(local),
- projection: None,
+ projection: box [],
}, _),
..
}) = stmt
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 =>
{
) => 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 =>
{
if let TerminatorKind::Call {
destination: Some((Place {
base: PlaceBase::Local(dest),
- projection: None,
+ projection: box [],
}, block)),
args,
..
let found_target = args.iter().any(|arg| {
if let Operand::Move(Place {
base: PlaceBase::Local(potential),
- projection: None,
+ projection: box [],
}) = arg {
*potential == target
} else {
) -> 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) {
let category = match *place {
Place {
base: PlaceBase::Local(RETURN_PLACE),
- projection: None,
+ projection: box [],
} => if let BorrowCheckContext {
universal_regions:
UniversalRegions {
},
Place {
base: PlaceBase::Local(l),
- projection: None,
+ projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
let category = match *dest {
Place {
base: PlaceBase::Local(RETURN_PLACE),
- projection: None,
+ projection: box [],
} => {
if let BorrowCheckContext {
universal_regions:
}
Place {
base: PlaceBase::Local(l),
- projection: None,
+ projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
// *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 {
// other field access
}
}
-
- // The "propagate" case. We need to check that our base is valid
- // for the borrow's lifetime.
- borrowed_projection = &proj.base;
}
}
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
}
}
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;
// 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 {
// 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 => {
}
}
- 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
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");
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.
// 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 {
| (ProjectionElem::Subslice { .. }, _)
| (ProjectionElem::Downcast(..), _) => bug!(
"mismatched projections in place_element_conflict: {:?} and {:?}",
- pi1,
- pi2
+ pi1_elem,
+ pi2_elem
),
}
}
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()]
}
}
// 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."),
}
}
}
);
if let Place {
base: PlaceBase::Local(user_local),
- projection: None,
+ projection: box [],
} = path.place {
self.mbcx.used_mut.insert(user_local);
}
kind: StaticKind::Static,
def_id: id,
})),
- projection: None,
+ projection: box [],
}),
ExprKind::PlaceTypeAscription { source, user_ty } => {
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(),
}
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,
// 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));
}
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;
}
// 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());
BorrowKind::Shallow,
Place {
base: place.base.clone(),
- projection: place.projection.clone(),
+ projection: place.projection.to_vec().into_boxed_slice(),
},
);
self.cfg.push_assign(
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)
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);
}
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(
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()))
_ 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();
path: MovePathIndex,
mut cond: F)
-> Option<MovePathIndex>
- 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;
}
// 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;
}
/// Maybe we should have separate "borrowck" and "moveck" modes.
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
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) => {
&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>) {
| TerminatorKind::Unreachable => {}
TerminatorKind::Return => {
- self.gather_move(&Place::RETURN_PLACE);
+ self.gather_move(&Place::return_place());
}
TerminatorKind::Assert { ref cond, .. } => {
// 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
{
// 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 {
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
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 {
// avoid allocations.
pub(super) fn eval_place_to_op(
&self,
- mir_place: &mir::Place<'tcx>,
+ place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> 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.
/// 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
// 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,
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 {
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))
)
);
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))
debug!("build_ctor: variant_index={:?}", variant_index);
let statements = expand_aggregate(
- Place::RETURN_PLACE,
+ Place::return_place(),
adt_def
.variants[variant_index]
.fields
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.
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.
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;
+ }
}
}
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) {
}
_ => {}
}
- projection = &proj.base;
}
}
}
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
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<Const<'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] {
StatementKind::Assign(
Place {
base: PlaceBase::Local(local),
- projection: None,
+ projection: box [],
},
box Rvalue::Use(ref operand)
) if local == dest_local => {
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 => {}
_ => {
// The source must be a local.
let src_local = if let Place {
base: PlaceBase::Local(local),
- projection: None,
+ projection: box [],
} = *src_place {
local
} else {
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,
}
}
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
- 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<Self::Path> {
- 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<Self::Path> {
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<Self::Path> {
- 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
})
}
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);
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);
}
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 {
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(),
}
}
// 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
kind: TerminatorKind::Drop {
location: Place {
base: PlaceBase::Local(local),
- projection: None,
+ projection: box [],
},
target,
unwind
// 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) {
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
match self.destination {
Place {
base: PlaceBase::Local(l),
- projection: None,
+ projection: box [],
} => {
*local = l;
return;
match place {
Place {
base: PlaceBase::Local(RETURN_PLACE),
- projection: None,
+ projection: box [],
} => {
// Return pointer; update the place itself
*place = self.destination.clone();
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))
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);
+ }
}
}
}
ty,
def_id,
}),
- projection: None,
+ projection: box [],
}
};
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
Operand::Move(Place {
base: mem::replace(
&mut place.base,
- promoted_place(ty, span).base
+ promoted_place(ty, span).base,
),
- projection: None,
+ projection: box [],
})
}
_ => bug!()
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.
match statement.kind {
StatementKind::Assign(Place {
base: PlaceBase::Local(index),
- projection: None,
+ projection: box [],
}, _) |
StatementKind::StorageLive(index) |
StatementKind::StorageDead(index) => {
match terminator.kind {
TerminatorKind::Drop { location: Place {
base: PlaceBase::Local(index),
- projection: None,
+ projection: box [],
}, target, .. } => {
if promoted(index) {
terminator.kind = TerminatorKind::Goto {
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),
}
}
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),
}
}
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,
});
}
}
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,
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() {
// 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`
_ => {},
}
- 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);
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 {
_,
box Rvalue::Ref(_, _, Place {
base: PlaceBase::Local(index),
- projection: None,
+ projection: box [],
})
) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index);
fn visit_projection(
&mut self,
place_base: &PlaceBase<'tcx>,
- proj: &Projection<'tcx>,
+ proj: &[PlaceElem<'tcx>],
context: PlaceContext,
location: Location,
) {
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()
+ }
}
}
}
// 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);
}
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);
}
}
}
),
};
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);
}
// 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)
TerminatorKind::Drop {
location: Place {
base: PlaceBase::Local(index),
- projection: None,
+ projection: box [],
},
target,
..
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(
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
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,
};
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,
location,
dst_place,
&src_place.base,
- proj,
+ &src_place.projection,
item_ty,
size as u32,
);
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,
- },
- }),
- }
- )
- )
- );
- }
- _ => {}
}
}
}
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 =
}
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(),
+ })),
+ );
}
}
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,
+ }))
+ }
}
}
}
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
}
_ => {}
}
- place_projection = &proj.base;
}
false
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))