Auto merge of #63420 - spastorino:place2_5, r=oli-obk

[Place 2.0] Convert Place's projection to a boxed slice

This is still work in progress, it's not compiling right now I need to review a bit more to see what's going on but wanted to open the PR to start discussing it.

r? @oli-obk
This commit is contained in:
bors 2019-09-13 15:37:15 +00:00
commit a6946a817a
61 changed files with 1602 additions and 1788 deletions

View file

@ -32,7 +32,6 @@ use rustc_serialize::{Encodable, Decodable};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write}; use std::fmt::{self, Debug, Display, Formatter, Write};
use std::iter::FusedIterator;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::slice; use std::slice;
use std::vec::IntoIter; use std::vec::IntoIter;
@ -1548,7 +1547,7 @@ pub struct Statement<'tcx> {
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
static_assert_size!(Statement<'_>, 56); static_assert_size!(Statement<'_>, 32);
impl Statement<'_> { impl Statement<'_> {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@ -1569,7 +1568,7 @@ impl Statement<'_> {
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
pub enum StatementKind<'tcx> { pub enum StatementKind<'tcx> {
/// Write the RHS Rvalue to the LHS Place. /// Write the RHS Rvalue to the LHS Place.
Assign(Place<'tcx>, Box<Rvalue<'tcx>>), Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
/// This represents all the reading that a pattern match may do /// This represents all the reading that a pattern match may do
/// (e.g., inspecting constants and discriminant values), and the /// (e.g., inspecting constants and discriminant values), and the
@ -1578,10 +1577,10 @@ pub enum StatementKind<'tcx> {
/// ///
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are /// Note that this also is emitted for regular `let` bindings to ensure that locals that are
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
FakeRead(FakeReadCause, Place<'tcx>), FakeRead(FakeReadCause, Box<Place<'tcx>>),
/// Write the discriminant for a variant to the enum Place. /// Write the discriminant for a variant to the enum Place.
SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx }, SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
/// Start a live range for the storage of the local. /// Start a live range for the storage of the local.
StorageLive(Local), StorageLive(Local),
@ -1598,7 +1597,7 @@ pub enum StatementKind<'tcx> {
/// by miri and only generated when "-Z mir-emit-retag" is passed. /// by miri and only generated when "-Z mir-emit-retag" is passed.
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
/// for more details. /// for more details.
Retag(RetagKind, Place<'tcx>), Retag(RetagKind, Box<Place<'tcx>>),
/// Encodes a user's type ascription. These need to be preserved /// Encodes a user's type ascription. These need to be preserved
/// intact so that NLL can respect them. For example: /// intact so that NLL can respect them. For example:
@ -1612,7 +1611,7 @@ pub enum StatementKind<'tcx> {
/// - `Contravariant` -- requires that `T_y :> T` /// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T` /// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect /// - `Bivariant` -- no effect
AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>), AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
/// No-op. Useful for deleting instructions without affecting statement indices. /// No-op. Useful for deleting instructions without affecting statement indices.
Nop, Nop,
@ -1676,7 +1675,7 @@ impl Debug for Statement<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::StatementKind::*; use self::StatementKind::*;
match self.kind { match self.kind {
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place), FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
Retag(ref kind, ref place) => write!( Retag(ref kind, ref place) => write!(
fmt, fmt,
@ -1697,7 +1696,7 @@ impl Debug for Statement<'_> {
InlineAsm(ref asm) => { InlineAsm(ref asm) => {
write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs) write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
} }
AscribeUserType(ref place, ref variance, ref c_ty) => { AscribeUserType(box(ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
} }
Nop => write!(fmt, "nop"), Nop => write!(fmt, "nop"),
@ -1717,7 +1716,7 @@ pub struct Place<'tcx> {
pub base: PlaceBase<'tcx>, pub base: PlaceBase<'tcx>,
/// projection out of a place (access a field, deref a pointer, etc) /// projection out of a place (access a field, deref a pointer, etc)
pub projection: Option<Box<Projection<'tcx>>>, pub projection: Box<[PlaceElem<'tcx>]>,
} }
#[derive( #[derive(
@ -1760,15 +1759,6 @@ impl_stable_hash_for!(struct Static<'tcx> {
def_id 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( #[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)] )]
@ -1850,14 +1840,22 @@ newtype_index! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlaceRef<'a, 'tcx> { pub struct PlaceRef<'a, 'tcx> {
pub base: &'a PlaceBase<'tcx>, pub base: &'a PlaceBase<'tcx>,
pub projection: &'a Option<Box<Projection<'tcx>>>, pub projection: &'a [PlaceElem<'tcx>],
} }
impl<'tcx> Place<'tcx> { impl<'tcx> Place<'tcx> {
pub const RETURN_PLACE: Place<'tcx> = Place { // FIXME change this back to a const when projection is a shared slice.
base: PlaceBase::Local(RETURN_PLACE), //
projection: None, // 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> { pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
self.elem(ProjectionElem::Field(f, ty)) self.elem(ProjectionElem::Field(f, ty))
@ -1883,9 +1881,13 @@ impl<'tcx> Place<'tcx> {
} }
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
// FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
let mut projection = self.projection.into_vec();
projection.push(elem);
Place { Place {
base: self.base, base: self.base,
projection: Some(Box::new(Projection { base: self.projection, elem })), projection: projection.into_boxed_slice(),
} }
} }
@ -1894,7 +1896,7 @@ impl<'tcx> Place<'tcx> {
/// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the /// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
/// same region of memory as its base. /// same region of memory as its base.
pub fn is_indirect(&self) -> bool { 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 /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
@ -1905,61 +1907,16 @@ impl<'tcx> Place<'tcx> {
match self { match self {
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} | } |
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(box Projection { projection: box [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
}),
} => Some(*local), } => Some(*local),
_ => None, _ => 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> { pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
PlaceRef { PlaceRef {
base: &self.base, base: &self.base,
@ -1972,7 +1929,7 @@ impl From<Local> for Place<'_> {
fn from(local: Local) -> Self { fn from(local: Local) -> Self {
Place { Place {
base: local.into(), base: local.into(),
projection: None, projection: Box::new([]),
} }
} }
} }
@ -1984,13 +1941,6 @@ impl From<Local> for PlaceBase<'_> {
} }
impl<'a, 'tcx> PlaceRef<'a, 'tcx> { 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 /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local. /// a single deref of a local.
// //
@ -1999,143 +1949,71 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
match self { match self {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} | } |
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(box Projection { projection: [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
}),
} => Some(*local), } => Some(*local),
_ => None, _ => 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<'_> { impl Debug for Place<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.iterate(|_place_base, place_projections| { for elem in self.projection.iter().rev() {
// FIXME: remove this collect once we have migrated to slices match elem {
let projs_vec: Vec<_> = place_projections.collect(); ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
for projection in projs_vec.iter().rev() { write!(fmt, "(").unwrap();
match projection.elem { }
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { ProjectionElem::Deref => {
write!(fmt, "(").unwrap(); write!(fmt, "(*").unwrap();
} }
ProjectionElem::Deref => { ProjectionElem::Index(_)
write!(fmt, "(*").unwrap(); | ProjectionElem::ConstantIndex { .. }
} | ProjectionElem::Subslice { .. } => {}
ProjectionElem::Index(_) }
| ProjectionElem::ConstantIndex { .. } }
| ProjectionElem::Subslice { .. } => {}
write!(fmt, "{:?}", self.base)?;
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)?;
} }
} }
}); }
self.iterate(|place_base, place_projections| { Ok(())
write!(fmt, "{:?}", place_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)?;
}
}
}
Ok(())
})
} }
} }
@ -3120,14 +2998,14 @@ BraceStructTypeFoldableImpl! {
EnumTypeFoldableImpl! { EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
(StatementKind::Assign)(a, b), (StatementKind::Assign)(a),
(StatementKind::FakeRead)(cause, place), (StatementKind::FakeRead)(cause, place),
(StatementKind::SetDiscriminant) { place, variant_index }, (StatementKind::SetDiscriminant) { place, variant_index },
(StatementKind::StorageLive)(a), (StatementKind::StorageLive)(a),
(StatementKind::StorageDead)(a), (StatementKind::StorageDead)(a),
(StatementKind::InlineAsm)(a), (StatementKind::InlineAsm)(a),
(StatementKind::Retag)(kind, place), (StatementKind::Retag)(kind, place),
(StatementKind::AscribeUserType)(a, v, b), (StatementKind::AscribeUserType)(a, v),
(StatementKind::Nop), (StatementKind::Nop),
} }
} }
@ -3409,30 +3287,26 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
} }
} }
impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> { impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
use crate::mir::ProjectionElem::*; use crate::mir::ProjectionElem::*;
let base = self.base.fold_with(folder); match self {
let elem = match self.elem {
Deref => Deref, Deref => Deref,
Field(f, ref ty) => Field(f, ty.fold_with(folder)), Field(f, ty) => Field(*f, ty.fold_with(folder)),
Index(ref v) => Index(v.fold_with(folder)), Index(v) => Index(v.fold_with(folder)),
ref elem => elem.clone(), elem => elem.clone(),
}; }
Projection { base, elem }
} }
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
use crate::mir::ProjectionElem::*; use crate::mir::ProjectionElem::*;
self.base.visit_with(visitor) match self {
|| match self.elem { Field(_, ty) => ty.visit_with(visitor),
Field(_, ref ty) => ty.visit_with(visitor), Index(v) => v.visit_with(visitor),
Index(ref v) => v.visit_with(visitor), _ => false,
_ => false, }
}
} }
} }

View file

@ -121,21 +121,16 @@ BraceStructTypeFoldableImpl! {
impl<'tcx> Place<'tcx> { impl<'tcx> Place<'tcx> {
pub fn ty_from<D>( pub fn ty_from<D>(
base: &PlaceBase<'tcx>, base: &PlaceBase<'tcx>,
projection: &Option<Box<Projection<'tcx>>>, projection: &[PlaceElem<'tcx>],
local_decls: &D, local_decls: &D,
tcx: TyCtxt<'tcx> tcx: TyCtxt<'tcx>
) -> PlaceTy<'tcx> ) -> PlaceTy<'tcx>
where D: HasLocalDecls<'tcx> where D: HasLocalDecls<'tcx>
{ {
Place::iterate_over(base, projection, |place_base, place_projections| { projection.iter().fold(
let mut place_ty = place_base.ty(local_decls); base.ty(local_decls),
|place_ty, elem| place_ty.projection_ty(tcx, elem)
for proj in place_projections { )
place_ty = place_ty.projection_ty(tcx, &proj.elem);
}
place_ty
})
} }
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>

View file

@ -152,18 +152,18 @@ macro_rules! make_mir_visitor {
} }
fn visit_place_base(&mut self, fn visit_place_base(&mut self,
place_base: & $($mutability)? PlaceBase<'tcx>, base: & $($mutability)? PlaceBase<'tcx>,
context: PlaceContext, context: PlaceContext,
location: Location) { location: Location) {
self.super_place_base(place_base, context, location); self.super_place_base(base, context, location);
} }
fn visit_projection(&mut self, fn visit_projection(&mut self,
place_base: & $($mutability)? PlaceBase<'tcx>, base: & $($mutability)? PlaceBase<'tcx>,
place: & $($mutability)? Projection<'tcx>, projection: & $($mutability)? [PlaceElem<'tcx>],
context: PlaceContext, context: PlaceContext,
location: Location) { location: Location) {
self.super_projection(place_base, place, context, location); self.super_projection(base, projection, context, location);
} }
fn visit_constant(&mut self, fn visit_constant(&mut self,
@ -344,7 +344,9 @@ macro_rules! make_mir_visitor {
self.visit_source_info(source_info); self.visit_source_info(source_info);
match kind { match kind {
StatementKind::Assign(place, rvalue) => { StatementKind::Assign(
box(ref $($mutability)? place, ref $($mutability)? rvalue)
) => {
self.visit_assign(place, rvalue, location); self.visit_assign(place, rvalue, location);
} }
StatementKind::FakeRead(_, place) => { StatementKind::FakeRead(_, place) => {
@ -391,7 +393,10 @@ macro_rules! make_mir_visitor {
StatementKind::Retag(kind, place) => { StatementKind::Retag(kind, place) => {
self.visit_retag(kind, place, location); self.visit_retag(kind, place, location);
} }
StatementKind::AscribeUserType(place, variance, user_ty) => { StatementKind::AscribeUserType(
box(ref $($mutability)? place, ref $($mutability)? user_ty),
variance
) => {
self.visit_ascribe_user_ty(place, variance, user_ty, location); self.visit_ascribe_user_ty(place, variance, user_ty, location);
} }
StatementKind::Nop => {} StatementKind::Nop => {}
@ -685,7 +690,7 @@ macro_rules! make_mir_visitor {
location: Location) { location: Location) {
let mut context = context; let mut context = context;
if place.projection.is_some() { if !place.projection.is_empty() {
context = if context.is_mutating_use() { context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection) PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else { } else {
@ -695,9 +700,10 @@ macro_rules! make_mir_visitor {
self.visit_place_base(& $($mutability)? place.base, context, location); self.visit_place_base(& $($mutability)? place.base, context, location);
if let Some(box proj) = & $($mutability)? place.projection { self.visit_projection(& $($mutability)? place.base,
self.visit_projection(& $($mutability)? place.base, proj, context, location); & $($mutability)? place.projection,
} context,
location);
} }
fn super_place_base(&mut self, fn super_place_base(&mut self,
@ -715,31 +721,31 @@ macro_rules! make_mir_visitor {
} }
fn super_projection(&mut self, fn super_projection(&mut self,
place_base: & $($mutability)? PlaceBase<'tcx>, base: & $($mutability)? PlaceBase<'tcx>,
proj: & $($mutability)? Projection<'tcx>, projection: & $($mutability)? [PlaceElem<'tcx>],
context: PlaceContext, context: PlaceContext,
location: Location) { location: Location) {
if let Some(box proj_base) = & $($mutability)? proj.base { if let [proj_base @ .., elem] = projection {
self.visit_projection(place_base, proj_base, context, location); self.visit_projection(base, proj_base, context, location);
}
match & $($mutability)? proj.elem { match elem {
ProjectionElem::Field(_field, ty) => { ProjectionElem::Field(_field, ty) => {
self.visit_ty(ty, TyContext::Location(location)); self.visit_ty(ty, TyContext::Location(location));
} }
ProjectionElem::Index(local) => { ProjectionElem::Index(local) => {
self.visit_local( self.visit_local(
local, local,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location location
); );
} }
ProjectionElem::Deref | ProjectionElem::Deref |
ProjectionElem::Subslice { from: _, to: _ } | ProjectionElem::Subslice { from: _, to: _ } |
ProjectionElem::ConstantIndex { offset: _, ProjectionElem::ConstantIndex { offset: _,
min_length: _, min_length: _,
from_end: _ } | from_end: _ } |
ProjectionElem::Downcast(_, _) => { ProjectionElem::Downcast(_, _) => {
}
} }
} }
} }

View file

@ -4,6 +4,7 @@
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(libc)] #![feature(libc)]
#![feature(slice_patterns)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(try_blocks)] #![feature(try_blocks)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]

View file

@ -105,7 +105,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
) { ) {
let cx = self.fx.cx; let cx = self.fx.cx;
if let Some(proj) = place_ref.projection { if let [proj_base @ .., elem] = place_ref.projection {
// Allow uses of projections that are ZSTs or from scalar fields. // Allow uses of projections that are ZSTs or from scalar fields.
let is_consume = match context { let is_consume = match context {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
@ -114,12 +114,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
}; };
if is_consume { if is_consume {
let base_ty = 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); let base_ty = self.fx.monomorphize(&base_ty);
// ZSTs don't require any actual memory access. // ZSTs don't require any actual memory access.
let elem_ty = base_ty let elem_ty = base_ty
.projection_ty(cx.tcx(), &proj.elem) .projection_ty(cx.tcx(), elem)
.ty; .ty;
let elem_ty = self.fx.monomorphize(&elem_ty); let elem_ty = self.fx.monomorphize(&elem_ty);
let span = if let mir::PlaceBase::Local(index) = place_ref.base { let span = if let mir::PlaceBase::Local(index) = place_ref.base {
@ -131,7 +131,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
return; return;
} }
if let mir::ProjectionElem::Field(..) = proj.elem { if let mir::ProjectionElem::Field(..) = elem {
let layout = cx.spanned_layout_of(base_ty.ty, span); let layout = cx.spanned_layout_of(base_ty.ty, span);
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
// Recurse with the same context, instead of `Projection`, // Recurse with the same context, instead of `Projection`,
@ -140,7 +140,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
self.process_place( self.process_place(
&mir::PlaceRef { &mir::PlaceRef {
base: place_ref.base, base: place_ref.base,
projection: &proj.base, projection: proj_base,
}, },
context, context,
location, location,
@ -151,11 +151,11 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
} }
// A deref projection only reads the pointer, never needs the place. // 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( self.process_place(
&mir::PlaceRef { &mir::PlaceRef {
base: place_ref.base, base: place_ref.base,
projection: &proj.base, projection: proj_base,
}, },
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location location
@ -168,7 +168,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
// visit_place API // visit_place API
let mut context = context; let mut context = context;
if place_ref.projection.is_some() { if !place_ref.projection.is_empty() {
context = if context.is_mutating_use() { context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection) PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else { } else {
@ -177,10 +177,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
} }
self.visit_place_base(place_ref.base, context, location); self.visit_place_base(place_ref.base, context, location);
self.visit_projection(place_ref.base, place_ref.projection, context, location);
if let Some(box proj) = place_ref.projection {
self.visit_projection(place_ref.base, proj, context, location);
}
} }
} }
@ -196,7 +193,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
if let mir::Place { if let mir::Place {
base: mir::PlaceBase::Local(index), base: mir::PlaceBase::Local(index),
projection: None, projection: box [],
} = *place { } = *place {
self.assign(index, location); self.assign(index, location);
let decl_span = self.fx.mir.local_decls[index].source_info.span; let decl_span = self.fx.mir.local_decls[index].source_info.span;

View file

@ -253,7 +253,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
PassMode::Direct(_) | PassMode::Pair(..) => { PassMode::Direct(_) | PassMode::Pair(..) => {
let op = 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 { if let Ref(llval, _, align) = op.val {
bx.load(llval, align) bx.load(llval, align)
} else { } else {
@ -612,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
ty, ty,
def_id: _, def_id: _,
}), }),
projection: None, projection: box [],
} }
) | ) |
mir::Operand::Move( mir::Operand::Move(
@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
ty, ty,
def_id: _, def_id: _,
}), }),
projection: None, projection: box [],
} }
) => { ) => {
let param_env = ty::ParamEnv::reveal_all(); let param_env = ty::ParamEnv::reveal_all();
@ -1105,7 +1105,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
let dest = if let mir::Place { let dest = if let mir::Place {
base: mir::PlaceBase::Local(index), base: mir::PlaceBase::Local(index),
projection: None, projection: box [],
} = *dest { } = *dest {
match self.locals[index] { match self.locals[index] {
LocalRef::Place(dest) => dest, LocalRef::Place(dest) => dest,
@ -1166,7 +1166,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) { ) {
if let mir::Place { if let mir::Place {
base: mir::PlaceBase::Local(index), base: mir::PlaceBase::Local(index),
projection: None, projection: box [],
} = *dst { } = *dst {
match self.locals[index] { match self.locals[index] {
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),

View file

@ -384,47 +384,45 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> Option<OperandRef<'tcx, Bx::Value>> { ) -> Option<OperandRef<'tcx, Bx::Value>> {
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
place_ref.iterate(|place_base, place_projection| { if let mir::PlaceBase::Local(index) = place_ref.base {
if let mir::PlaceBase::Local(index) = place_base { match self.locals[*index] {
match self.locals[*index] { LocalRef::Operand(Some(mut o)) => {
LocalRef::Operand(Some(mut o)) => { // Moves out of scalar and scalar pair fields are trivial.
// Moves out of scalar and scalar pair fields are trivial. for elem in place_ref.projection.iter() {
for proj in place_projection { match elem {
match proj.elem { mir::ProjectionElem::Field(ref f, _) => {
mir::ProjectionElem::Field(ref f, _) => { o = o.extract_field(bx, f.index());
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,
} }
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,
} }
}
Some(o) Some(o)
} }
LocalRef::Operand(None) => { LocalRef::Operand(None) => {
bug!("use of {:?} before def", place_ref); bug!("use of {:?} before def", place_ref);
} }
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
// watch out for locals that do not have an // watch out for locals that do not have an
// alloca; they are handled somewhat differently // alloca; they are handled somewhat differently
None None
}
} }
} else {
None
} }
}) } else {
None
}
} }
pub fn codegen_consume( pub fn codegen_consume(

View file

@ -449,7 +449,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let result = match &place_ref { let result = match &place_ref {
mir::PlaceRef { mir::PlaceRef {
base: mir::PlaceBase::Local(index), base: mir::PlaceBase::Local(index),
projection: None, projection: [],
} => { } => {
match self.locals[*index] { match self.locals[*index] {
LocalRef::Place(place) => { LocalRef::Place(place) => {
@ -469,7 +469,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
kind: mir::StaticKind::Promoted(promoted, substs), kind: mir::StaticKind::Promoted(promoted, substs),
def_id, def_id,
}), }),
projection: None, projection: [],
} => { } => {
let param_env = ty::ParamEnv::reveal_all(); let param_env = ty::ParamEnv::reveal_all();
let instance = Instance::new(*def_id, self.monomorphize(substs)); let instance = Instance::new(*def_id, self.monomorphize(substs));
@ -504,7 +504,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
kind: mir::StaticKind::Static, kind: mir::StaticKind::Static,
def_id, def_id,
}), }),
projection: None, projection: [],
} => { } => {
// NB: The layout of a static may be unsized as is the case when working // NB: The layout of a static may be unsized as is the case when working
// with a static that is an extern_type. // with a static that is an extern_type.
@ -514,10 +514,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}, },
mir::PlaceRef { mir::PlaceRef {
base, base,
projection: Some(box mir::Projection { projection: [proj_base @ .., mir::ProjectionElem::Deref],
base: proj_base,
elem: mir::ProjectionElem::Deref,
}),
} => { } => {
// Load the pointer from its location. // Load the pointer from its location.
self.codegen_consume(bx, &mir::PlaceRef { self.codegen_consume(bx, &mir::PlaceRef {
@ -527,22 +524,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
mir::PlaceRef { mir::PlaceRef {
base, base,
projection: Some(projection), projection: [proj_base @ .., elem],
} => { } => {
// FIXME turn this recursion into iteration // FIXME turn this recursion into iteration
let cg_base = self.codegen_place(bx, &mir::PlaceRef { let cg_base = self.codegen_place(bx, &mir::PlaceRef {
base, base,
projection: &projection.base, projection: proj_base,
}); });
match projection.elem { match elem {
mir::ProjectionElem::Deref => bug!(), mir::ProjectionElem::Deref => bug!(),
mir::ProjectionElem::Field(ref field, _) => { mir::ProjectionElem::Field(ref field, _) => {
cg_base.project_field(bx, field.index()) cg_base.project_field(bx, field.index())
} }
mir::ProjectionElem::Index(index) => { mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy( let index = &mir::Operand::Copy(
mir::Place::from(index) mir::Place::from(*index)
); );
let index = self.codegen_operand(bx, index); let index = self.codegen_operand(bx, index);
let llindex = index.immediate(); let llindex = index.immediate();
@ -551,27 +548,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::ProjectionElem::ConstantIndex { offset, mir::ProjectionElem::ConstantIndex { offset,
from_end: false, from_end: false,
min_length: _ } => { 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) cg_base.project_index(bx, lloffset)
} }
mir::ProjectionElem::ConstantIndex { offset, mir::ProjectionElem::ConstantIndex { offset,
from_end: true, from_end: true,
min_length: _ } => { 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 lllen = cg_base.len(bx.cx());
let llindex = bx.sub(lllen, lloffset); let llindex = bx.sub(lllen, lloffset);
cg_base.project_index(bx, llindex) cg_base.project_index(bx, llindex)
} }
mir::ProjectionElem::Subslice { from, to } => { mir::ProjectionElem::Subslice { from, to } => {
let mut subslice = cg_base.project_index(bx, 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) 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)); subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
if subslice.layout.is_unsized() { if subslice.layout.is_unsized() {
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(), 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 // Cast the place pointer type to the new
@ -582,7 +579,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
subslice subslice
} }
mir::ProjectionElem::Downcast(_, v) => { mir::ProjectionElem::Downcast(_, v) => {
cg_base.project_downcast(bx, v) cg_base.project_downcast(bx, *v)
} }
} }
} }

View file

@ -522,7 +522,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// because codegen_place() panics if Local is operand. // because codegen_place() panics if Local is operand.
if let mir::Place { if let mir::Place {
base: mir::PlaceBase::Local(index), base: mir::PlaceBase::Local(index),
projection: None, projection: box [],
} = *place { } = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] { if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::Array(_, n) = op.layout.ty.sty { if let ty::Array(_, n) = op.layout.ty.sty {

View file

@ -16,12 +16,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(&mut bx, statement.source_info); self.set_debug_loc(&mut bx, statement.source_info);
match statement.kind { match statement.kind {
mir::StatementKind::Assign(ref place, ref rvalue) => { mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
if let mir::Place { if let mir::Place {
base: mir::PlaceBase::Local(index), base: mir::PlaceBase::Local(index),
projection: None, projection: box [],
} = *place { } = place {
match self.locals[index] { match self.locals[*index] {
LocalRef::Place(cg_dest) => { LocalRef::Place(cg_dest) => {
self.codegen_rvalue(bx, cg_dest, rvalue) self.codegen_rvalue(bx, cg_dest, rvalue)
} }
@ -30,7 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
LocalRef::Operand(None) => { LocalRef::Operand(None) => {
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
if let Some(name) = self.mir.local_decls[index].name { if let Some(name) = self.mir.local_decls[*index].name {
match operand.val { match operand.val {
OperandValue::Ref(x, ..) | OperandValue::Ref(x, ..) |
OperandValue::Immediate(x) => { OperandValue::Immediate(x) => {
@ -44,7 +44,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
} }
} }
self.locals[index] = LocalRef::Operand(Some(operand)); self.locals[*index] = LocalRef::Operand(Some(operand));
bx bx
} }
LocalRef::Operand(Some(op)) => { LocalRef::Operand(Some(op)) => {
@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_rvalue(bx, cg_dest, rvalue) self.codegen_rvalue(bx, cg_dest, rvalue)
} }
} }
mir::StatementKind::SetDiscriminant{ref place, variant_index} => { mir::StatementKind::SetDiscriminant{box ref place, variant_index} => {
self.codegen_place(&mut bx, &place.as_ref()) self.codegen_place(&mut bx, &place.as_ref())
.codegen_set_discr(&mut bx, variant_index); .codegen_set_discr(&mut bx, variant_index);
bx bx

View file

@ -317,7 +317,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
// so extract `temp`. // so extract `temp`.
let temp = if let &mir::Place { let temp = if let &mir::Place {
base: mir::PlaceBase::Local(temp), base: mir::PlaceBase::Local(temp),
projection: None, projection: box [],
} = assigned_place { } = assigned_place {
temp temp
} else { } else {

View file

@ -2,8 +2,8 @@ use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::mir::{ use rustc::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local, self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, Statement, StatementKind, TerminatorKind, VarBindingForm,
}; };
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
@ -244,7 +244,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
let span = if let Place { let span = if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = place { } = place {
let decl = &self.body.local_decls[*local]; let decl = &self.body.local_decls[*local];
Some(decl.source_info.span) Some(decl.source_info.span)
@ -614,17 +614,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection, projection,
} = first_borrowed_place; } = first_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: base_proj, elem }) = current {
match elem { match elem {
ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => { ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
return Some((PlaceRef { return Some((PlaceRef {
base: base, base: base,
projection: base_proj, projection: proj_base,
}, field)); }, field));
}, },
_ => current = base_proj, _ => {},
} }
} }
None None
@ -637,9 +637,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
projection, projection,
} = second_borrowed_place; } = 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 ProjectionElem::Field(field, _) = elem {
if let Some(union_ty) = union_ty(base, proj_base) { if let Some(union_ty) = union_ty(base, proj_base) {
if field != target_field if field != target_field
@ -660,8 +660,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
} }
} }
current = proj_base;
} }
None None
}) })
@ -707,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.var_or_use(); 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 { let proper_span = match root_place.base {
PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span, PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
_ => drop_span, _ => drop_span,
@ -716,7 +714,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.access_place_error_reported if self.access_place_error_reported
.contains(&(Place { .contains(&(Place {
base: root_place.base.clone(), base: root_place.base.clone(),
projection: root_place.projection.clone(), projection: root_place.projection.to_vec().into_boxed_slice(),
}, borrow_span)) }, borrow_span))
{ {
debug!( debug!(
@ -729,7 +727,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.access_place_error_reported self.access_place_error_reported
.insert((Place { .insert((Place {
base: root_place.base.clone(), base: root_place.base.clone(),
projection: root_place.projection.clone(), projection: root_place.projection.to_vec().into_boxed_slice(),
}, borrow_span)); }, borrow_span));
if let StorageDeadOrDrop::Destructor(dropped_ty) = if let StorageDeadOrDrop::Destructor(dropped_ty) =
@ -1107,7 +1105,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let local_kind = match borrow.borrowed_place { let local_kind = match borrow.borrowed_place {
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} => { } => {
match self.body.local_kind(local) { match self.body.local_kind(local) {
LocalKind::ReturnPointer LocalKind::ReturnPointer
@ -1136,7 +1134,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.unwrap(); .unwrap();
let local = if let PlaceRef { let local = if let PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} = root_place { } = root_place {
local local
} else { } else {
@ -1446,7 +1444,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) { ) {
let (from_arg, local_decl) = if let Place { let (from_arg, local_decl) = if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = *err_place { } = *err_place {
if let LocalKind::Arg = self.body.local_kind(local) { if let LocalKind::Arg = self.body.local_kind(local) {
(true, Some(&self.body.local_decls[local])) (true, Some(&self.body.local_decls[local]))
@ -1519,20 +1517,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> { fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
match place.projection { match place.projection {
None => { [] => {
StorageDeadOrDrop::LocalStorageDead StorageDeadOrDrop::LocalStorageDead
} }
Some(box Projection { ref base, ref elem }) => { [proj_base @ .., elem] => {
// FIXME(spastorino) make this iterate
let base_access = self.classify_drop_access_kind(PlaceRef { let base_access = self.classify_drop_access_kind(PlaceRef {
base: place.base, base: place.base,
projection: base, projection: proj_base,
}); });
match elem { match elem {
ProjectionElem::Deref => match base_access { ProjectionElem::Deref => match base_access {
StorageDeadOrDrop::LocalStorageDead StorageDeadOrDrop::LocalStorageDead
| StorageDeadOrDrop::BoxedStorageDead => { | StorageDeadOrDrop::BoxedStorageDead => {
assert!( assert!(
Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(), Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(),
"Drop of value behind a reference or raw pointer" "Drop of value behind a reference or raw pointer"
); );
StorageDeadOrDrop::BoxedStorageDead StorageDeadOrDrop::BoxedStorageDead
@ -1540,7 +1539,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
StorageDeadOrDrop::Destructor(_) => base_access, StorageDeadOrDrop::Destructor(_) => base_access,
}, },
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty; let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
match base_ty.sty { match base_ty.sty {
ty::Adt(def, _) if def.has_dtor(tcx) => { ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor // Report the outermost adt with a destructor
@ -1598,7 +1597,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"annotate_argument_and_return_for_borrow: location={:?}", "annotate_argument_and_return_for_borrow: location={:?}",
location location
); );
if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..}) if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
= &self.body[location.block].statements.get(location.statement_index) = &self.body[location.block].statements.get(location.statement_index)
{ {
debug!( debug!(
@ -1609,7 +1608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut target = *match reservation { let mut target = *match reservation {
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} if self.body.local_kind(*local) == LocalKind::Temp => local, } if self.body.local_kind(*local) == LocalKind::Temp => local,
_ => return None, _ => return None,
}; };
@ -1623,11 +1622,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
target, stmt target, stmt
); );
if let StatementKind::Assign( if let StatementKind::Assign(
Place { box(
base: PlaceBase::Local(assigned_to), Place {
projection: None, base: PlaceBase::Local(assigned_to),
}, projection: box [],
box rvalue },
rvalue
)
) = &stmt.kind { ) = &stmt.kind {
debug!( debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} \ "annotate_argument_and_return_for_borrow: assigned_to={:?} \
@ -1753,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let TerminatorKind::Call { if let TerminatorKind::Call {
destination: Some((Place { destination: Some((Place {
base: PlaceBase::Local(assigned_to), base: PlaceBase::Local(assigned_to),
projection: None, projection: box [],
}, _)), }, _)),
args, args,
.. ..

View file

@ -41,7 +41,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut target = place.local_or_deref_local(); let mut target = place.local_or_deref_local();
for stmt in &self.body[location.block].statements[location.statement_index..] { for stmt in &self.body[location.block].statements[location.statement_index..] {
debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target); debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind { if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from); debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
match from { match from {
Operand::Copy(ref place) | Operand::Copy(ref place) |
@ -152,7 +152,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match place { match place {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} => { } => {
self.append_local_to_string(*local, buf)?; self.append_local_to_string(*local, buf)?;
} }
@ -162,7 +162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
.. ..
}), }),
projection: None, projection: [],
} => { } => {
buf.push_str("promoted"); buf.push_str("promoted");
} }
@ -173,15 +173,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id, def_id,
.. ..
}), }),
projection: None, projection: [],
} => { } => {
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string()); buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
} }
PlaceRef { PlaceRef {
base, base,
projection: Some(ref proj), projection: [proj_base @ .., elem],
} => { } => {
match proj.elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let upvar_field_projection = let upvar_field_projection =
self.is_upvar_field_projection(place); self.is_upvar_field_projection(place);
@ -199,20 +199,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
&including_downcast, &including_downcast,
)?; )?;
} else { } else {
match (&proj.base, base) { match (proj_base, base) {
(None, PlaceBase::Local(local)) => { ([], PlaceBase::Local(local)) => {
if self.body.local_decls[*local].is_ref_for_guard() { if self.body.local_decls[*local].is_ref_for_guard() {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
@ -224,7 +224,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
@ -238,7 +238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
@ -253,7 +253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
@ -275,12 +275,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else { } else {
let field_name = self.describe_field(PlaceRef { let field_name = self.describe_field(PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, field); }, *field);
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
@ -295,14 +295,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
&including_downcast, &including_downcast,
)?; )?;
buf.push_str("["); 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("_");
} }
buf.push_str("]"); buf.push_str("]");
@ -315,7 +315,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.append_place_to_string( self.append_place_to_string(
PlaceRef { PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, },
buf, buf,
autoderef, autoderef,
@ -349,28 +349,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match place { match place {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} => { } => {
let local = &self.body.local_decls[*local]; let local = &self.body.local_decls[*local];
self.describe_field_from_ty(&local.ty, field, None) self.describe_field_from_ty(&local.ty, field, None)
} }
PlaceRef { PlaceRef {
base: PlaceBase::Static(static_), base: PlaceBase::Static(static_),
projection: None, projection: [],
} => } =>
self.describe_field_from_ty(&static_.ty, field, None), self.describe_field_from_ty(&static_.ty, field, None),
PlaceRef { PlaceRef {
base, base,
projection: Some(proj), projection: [proj_base @ .., elem],
} => match proj.elem { } => match elem {
ProjectionElem::Deref => self.describe_field(PlaceRef { ProjectionElem::Deref => {
base, self.describe_field(PlaceRef {
projection: &proj.base, base,
}, field), projection: proj_base,
}, field)
}
ProjectionElem::Downcast(_, variant_index) => { ProjectionElem::Downcast(_, variant_index) => {
let base_ty = let base_ty =
Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).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) => { ProjectionElem::Field(_, field_type) => {
self.describe_field_from_ty(&field_type, field, None) self.describe_field_from_ty(&field_type, field, None)
@ -380,7 +382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ProjectionElem::Subslice { .. } => { | ProjectionElem::Subslice { .. } => {
self.describe_field(PlaceRef { self.describe_field(PlaceRef {
base, base,
projection: &proj.base, projection: proj_base,
}, field) }, field)
} }
}, },
@ -445,7 +447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id, def_id,
.. ..
}), }),
projection: None, projection: [],
} = place_ref { } = place_ref {
let attrs = self.infcx.tcx.get_attrs(*def_id); let attrs = self.infcx.tcx.get_attrs(*def_id);
let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
@ -790,8 +792,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
if let StatementKind::Assign( if let StatementKind::Assign(
_, box(_, Rvalue::Aggregate(ref kind, ref places))
box Rvalue::Aggregate(ref kind, ref places)
) = stmt.kind { ) = stmt.kind {
let (def_id, is_generator) = match kind { let (def_id, is_generator) = match kind {
box AggregateKind::Closure(def_id, _) => (def_id, false), box AggregateKind::Closure(def_id, _) => (def_id, false),
@ -828,10 +829,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.get(location.statement_index) .get(location.statement_index)
{ {
Some(&Statement { Some(&Statement {
kind: StatementKind::Assign(Place { kind: StatementKind::Assign(box(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}, _), }, _)),
.. ..
}) => local, }) => local,
_ => return OtherUse(use_span), _ => return OtherUse(use_span),
@ -844,7 +845,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for stmt in &self.body[location.block].statements[location.statement_index + 1..] { for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
if let StatementKind::Assign( if let StatementKind::Assign(
_, box Rvalue::Aggregate(ref kind, ref places) box(_, Rvalue::Aggregate(ref kind, ref places))
) = stmt.kind { ) = stmt.kind {
let (def_id, is_generator) = match kind { let (def_id, is_generator) = match kind {
box AggregateKind::Closure(def_id, _) => (def_id, false), box AggregateKind::Closure(def_id, _) => (def_id, false),

View file

@ -10,10 +10,10 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
use rustc::middle::borrowck::SignalledError; use rustc::middle::borrowck::SignalledError;
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{ use rustc::mir::{
ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef, ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem,
Static, StaticKind 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::mir::{Terminator, TerminatorKind};
use rustc::ty::query::Providers; use rustc::ty::query::Providers;
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
@ -546,7 +546,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
self.check_activations(location, span, flow_state); self.check_activations(location, span, flow_state);
match stmt.kind { match stmt.kind {
StatementKind::Assign(ref lhs, ref rhs) => { StatementKind::Assign(box(ref lhs, ref rhs)) => {
self.consume_rvalue( self.consume_rvalue(
location, location,
(rhs, span), (rhs, span),
@ -561,7 +561,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
flow_state, flow_state,
); );
} }
StatementKind::FakeRead(_, ref place) => { StatementKind::FakeRead(_, box ref place) => {
// Read for match doesn't access any memory and is used to // Read for match doesn't access any memory and is used to
// assert that a place is safe and live. So we don't have to // assert that a place is safe and live. So we don't have to
// do any checks here. // do any checks here.
@ -905,7 +905,7 @@ enum InitializationRequiringAction {
struct RootPlace<'d, 'tcx> { struct RootPlace<'d, 'tcx> {
place_base: &'d PlaceBase<'tcx>, place_base: &'d PlaceBase<'tcx>,
place_projection: &'d Option<Box<Projection<'tcx>>>, place_projection: &'d [PlaceElem<'tcx>],
is_local_mutation_allowed: LocalMutationIsAllowed, is_local_mutation_allowed: LocalMutationIsAllowed,
} }
@ -1191,7 +1191,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// before (at this point in the flow). // before (at this point in the flow).
if let Place { if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = place_span.0 { } = place_span.0 {
if let Mutability::Not = self.body.local_decls[*local].mutability { if let Mutability::Not = self.body.local_decls[*local].mutability {
// check for reassignments to immutable local variables // check for reassignments to immutable local variables
@ -1331,7 +1331,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'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()) { if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
this.used_mut_upvars.push(field); this.used_mut_upvars.push(field);
} }
@ -1346,11 +1346,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match *operand { match *operand {
Operand::Move(Place { Operand::Move(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}) | }) |
Operand::Copy(Place { Operand::Copy(Place {
base: PlaceBase::Local(local), 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].is_user_variable.is_none() => {
if self.body.local_decls[local].ty.is_mutable_ptr() { if self.body.local_decls[local].ty.is_mutable_ptr() {
// The variable will be marked as mutable by the borrow. // The variable will be marked as mutable by the borrow.
@ -1387,7 +1387,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let stmt = &bbd.statements[loc.statement_index]; let stmt = &bbd.statements[loc.statement_index];
debug!("temporary assigned in: stmt={:?}", stmt); debug!("temporary assigned in: stmt={:?}", stmt);
if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind { if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
propagate_closure_used_mut_place(self, source); propagate_closure_used_mut_place(self, source);
} else { } else {
bug!("closures should only capture user variables \ bug!("closures should only capture user variables \
@ -1468,7 +1468,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// //
// FIXME: allow thread-locals to borrow other thread locals? // 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 { let (might_be_alive, will_be_dropped) = match root_place.base {
PlaceBase::Static(box Static { PlaceBase::Static(box Static {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
@ -1756,13 +1756,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
flow_state: &Flows<'cx, 'tcx>, flow_state: &Flows<'cx, 'tcx>,
) { ) {
debug!("check_if_assigned_path_is_moved place: {:?}", place); 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. // None case => assigning to `x` does not require `x` be initialized.
while let Some(proj) = place_projection { for (i, elem) in place.projection.iter().enumerate().rev() {
let Projection { ref base, ref elem } = **proj; match elem {
match *elem {
ProjectionElem::Index(_/*operand*/) | ProjectionElem::Index(_/*operand*/) |
ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid. // assigning to P[i] requires P to be valid.
@ -1774,11 +1771,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// assigning to (*P) requires P to be initialized // assigning to (*P) requires P to be initialized
ProjectionElem::Deref => { ProjectionElem::Deref => {
let proj_base = &place.projection[..i];
self.check_if_full_path_is_moved( self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use, location, InitializationRequiringAction::Use,
(PlaceRef { (PlaceRef {
base: &place.base, base: &place.base,
projection: base, projection: proj_base,
}, span), flow_state); }, span), flow_state);
// (base initialized; no need to // (base initialized; no need to
// recur further) // recur further)
@ -1791,18 +1790,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
ProjectionElem::Field(..) => { ProjectionElem::Field(..) => {
let proj_base = &place.projection[..i];
// if type of `P` has a dtor, then // if type of `P` has a dtor, then
// assigning to `P.f` requires `P` itself // assigning to `P.f` requires `P` itself
// be already initialized // be already initialized
let tcx = self.infcx.tcx; 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 { match base_ty.sty {
ty::Adt(def, _) if def.has_dtor(tcx) => { ty::Adt(def, _) if def.has_dtor(tcx) => {
self.check_if_path_or_subpath_is_moved( self.check_if_path_or_subpath_is_moved(
location, InitializationRequiringAction::Assignment, location, InitializationRequiringAction::Assignment,
(PlaceRef { (PlaceRef {
base: &place.base, base: &place.base,
projection: base, projection: proj_base,
}, span), flow_state); }, span), flow_state);
// (base initialized; no need to // (base initialized; no need to
@ -1815,7 +1815,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Adt(..) | ty::Tuple(..) => { ty::Adt(..) | ty::Tuple(..) => {
check_parent_of_field(self, location, PlaceRef { check_parent_of_field(self, location, PlaceRef {
base: &place.base, base: &place.base,
projection: base, projection: proj_base,
}, span, flow_state); }, span, flow_state);
if let PlaceBase::Local(local) = place.base { if let PlaceBase::Local(local) = place.base {
@ -1835,8 +1835,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
} }
} }
place_projection = base;
} }
fn check_parent_of_field<'cx, 'tcx>( fn check_parent_of_field<'cx, 'tcx>(
@ -2084,7 +2082,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match root_place { match root_place {
RootPlace { RootPlace {
place_base: PlaceBase::Local(local), place_base: PlaceBase::Local(local),
place_projection: None, place_projection: [],
is_local_mutation_allowed, is_local_mutation_allowed,
} => { } => {
// If the local may have been initialized, and it is now currently being // If the local may have been initialized, and it is now currently being
@ -2103,7 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} => {} } => {}
RootPlace { RootPlace {
place_base, place_base,
place_projection: place_projection @ Some(_), place_projection: place_projection @ [.., _],
is_local_mutation_allowed: _, is_local_mutation_allowed: _,
} => { } => {
if let Some(field) = self.is_upvar_field_projection(PlaceRef { if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@ -2115,7 +2113,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
RootPlace { RootPlace {
place_base: PlaceBase::Static(..), place_base: PlaceBase::Static(..),
place_projection: None, place_projection: [],
is_local_mutation_allowed: _, is_local_mutation_allowed: _,
} => {} } => {}
} }
@ -2131,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match place { match place {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} => { } => {
let local = &self.body.local_decls[*local]; let local = &self.body.local_decls[*local];
match local.mutability { match local.mutability {
@ -2162,7 +2160,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
.. ..
}), }),
projection: None, projection: [],
} => } =>
Ok(RootPlace { Ok(RootPlace {
place_base: place.base, place_base: place.base,
@ -2175,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id, def_id,
.. ..
}), }),
projection: None, projection: [],
} => { } => {
if !self.infcx.tcx.is_mutable_static(*def_id) { if !self.infcx.tcx.is_mutable_static(*def_id) {
Err(place) Err(place)
@ -2189,12 +2187,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
PlaceRef { PlaceRef {
base: _, base: _,
projection: Some(proj), projection: [proj_base @ .., elem],
} => { } => {
match proj.elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let base_ty = 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 // Check the kind of deref to decide
match base_ty.sty { match base_ty.sty {
@ -2216,7 +2214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.is_mutable(PlaceRef { self.is_mutable(PlaceRef {
base: place.base, base: place.base,
projection: &proj.base, projection: proj_base,
}, mode) }, mode)
} }
} }
@ -2240,7 +2238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
_ if base_ty.is_box() => { _ if base_ty.is_box() => {
self.is_mutable(PlaceRef { self.is_mutable(PlaceRef {
base: place.base, base: place.base,
projection: &proj.base, projection: proj_base,
}, is_local_mutation_allowed) }, is_local_mutation_allowed)
} }
// Deref should only be for reference, pointers or boxes // Deref should only be for reference, pointers or boxes
@ -2297,7 +2295,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// ``` // ```
let _ = self.is_mutable(PlaceRef { let _ = self.is_mutable(PlaceRef {
base: place.base, base: place.base,
projection: &proj.base, projection: proj_base,
}, is_local_mutation_allowed)?; }, is_local_mutation_allowed)?;
Ok(RootPlace { Ok(RootPlace {
place_base: place.base, place_base: place.base,
@ -2309,7 +2307,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else { } else {
self.is_mutable(PlaceRef { self.is_mutable(PlaceRef {
base: place.base, base: place.base,
projection: &proj.base, projection: proj_base,
}, is_local_mutation_allowed) }, is_local_mutation_allowed)
} }
} }
@ -2326,21 +2324,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut place_projection = place_ref.projection; let mut place_projection = place_ref.projection;
let mut by_ref = false; let mut by_ref = false;
if let Some(box Projection { if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
base, place_projection = proj_base;
elem: ProjectionElem::Deref,
}) = place_projection {
place_projection = &base;
by_ref = true; by_ref = true;
} }
match place_projection { match place_projection {
Some(box Projection { [base @ .., ProjectionElem::Field(field, _ty)] => {
base,
elem: ProjectionElem::Field(field, _ty),
}) => {
let tcx = self.infcx.tcx; 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()) && if (base_ty.is_closure() || base_ty.is_generator()) &&
(!by_ref || self.upvars[field.index()].by_ref) { (!by_ref || self.upvars[field.index()].by_ref) {

View file

@ -89,11 +89,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// If that ever stops being the case, then the ever initialized // If that ever stops being the case, then the ever initialized
// flow could be used. // flow could be used.
if let Some(StatementKind::Assign( if let Some(StatementKind::Assign(
Place { box(
base: PlaceBase::Local(local), Place {
projection: None, base: PlaceBase::Local(local),
}, projection: box [],
box Rvalue::Use(Operand::Move(move_from)), },
Rvalue::Use(Operand::Move(move_from))
)
)) = self.body.basic_blocks()[location.block] )) = self.body.basic_blocks()[location.block]
.statements .statements
.get(location.statement_index) .get(location.statement_index)
@ -274,16 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
place: &Place<'tcx>, place: &Place<'tcx>,
span: Span span: Span
) -> DiagnosticBuilder<'a> { ) -> 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()) format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
} else { } 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 { let base_static = PlaceRef {
base: &place.base, base: &place.base,
projection: base_static, projection: &place.projection[..1],
}; };
format!( format!(
@ -309,17 +307,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p)); .find_map(|p| self.is_upvar_field_projection(p));
let deref_base = match deref_target_place.projection { let deref_base = match &deref_target_place.projection {
Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef { box [proj_base @ .., ProjectionElem::Deref] => {
base: &deref_target_place.base, PlaceRef {
projection: base, base: &deref_target_place.base,
}, projection: proj_base,
}
}
_ => bug!("deref_target_place is not a deref projection"), _ => bug!("deref_target_place is not a deref projection"),
}; };
if let PlaceRef { if let PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} = deref_base { } = deref_base {
let decl = &self.body.local_decls[*local]; let decl = &self.body.local_decls[*local];
if decl.is_ref_for_guard() { if decl.is_ref_for_guard() {

View file

@ -2,7 +2,7 @@ use rustc::hir;
use rustc::hir::Node; use rustc::hir::Node;
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body}; use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
use rustc::mir::{ 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::ty::{self, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
@ -47,12 +47,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match the_place_err { match the_place_err {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} => { } => {
item_msg = format!("`{}`", access_place_desc.unwrap()); item_msg = format!("`{}`", access_place_desc.unwrap());
if let Place { if let Place {
base: PlaceBase::Local(_), base: PlaceBase::Local(_),
projection: None, projection: box [],
} = access_place { } = access_place {
reason = ", as it is not declared as mutable".to_string(); reason = ", as it is not declared as mutable".to_string();
} else { } else {
@ -65,14 +65,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { PlaceRef {
base: _, base: _,
projection: projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
Some(box Projection {
base,
elem: ProjectionElem::Field(upvar_index, _),
}),
} => { } => {
debug_assert!(is_closure_or_generator( 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()); item_msg = format!("`{}`", access_place_desc.unwrap());
@ -86,14 +82,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { PlaceRef {
base: _, base: _,
projection: projection: [proj_base @ .., ProjectionElem::Deref],
Some(box Projection {
base,
elem: ProjectionElem::Deref,
}),
} => { } => {
if the_place_err.base == &PlaceBase::Local(Local::new(1)) && if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
base.is_none() && proj_base.is_empty() &&
!self.upvars.is_empty() { !self.upvars.is_empty() {
item_msg = format!("`{}`", access_place_desc.unwrap()); item_msg = format!("`{}`", access_place_desc.unwrap());
debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
@ -114,7 +106,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
", as `Fn` closures cannot mutate their captured variables".to_string() ", as `Fn` closures cannot mutate their captured variables".to_string()
} }
} else if { } else if {
if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) { if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) {
self.body.local_decls[*local].is_ref_for_guard() self.body.local_decls[*local].is_ref_for_guard()
} else { } else {
false false
@ -125,7 +117,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else { } else {
let source = self.borrowed_content_source(PlaceRef { let source = self.borrowed_content_source(PlaceRef {
base: the_place_err.base, base: the_place_err.base,
projection: base, projection: proj_base,
}); });
let pointer_type = source.describe_for_immutable_place(); let pointer_type = source.describe_for_immutable_place();
opt_source = Some(source); opt_source = Some(source);
@ -151,7 +143,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
.. ..
}), }),
projection: None, projection: [],
} => unreachable!(), } => unreachable!(),
PlaceRef { PlaceRef {
@ -161,11 +153,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
def_id, def_id,
.. ..
}), }),
projection: None, projection: [],
} => { } => {
if let Place { if let Place {
base: PlaceBase::Static(_), base: PlaceBase::Static(_),
projection: None, projection: box [],
} = access_place { } = access_place {
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap()); item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
reason = String::new(); reason = String::new();
@ -178,33 +170,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { PlaceRef {
base: _, base: _,
projection: projection: [.., ProjectionElem::Index(_)],
Some(box Projection {
base: _,
elem: ProjectionElem::Index(_),
}),
} }
| PlaceRef { | PlaceRef {
base: _, base: _,
projection: projection: [.., ProjectionElem::ConstantIndex { .. }],
Some(box Projection {
base: _,
elem: ProjectionElem::ConstantIndex { .. },
}),
} }
| PlaceRef { | PlaceRef {
base: _, base: _,
projection: Some(box Projection { projection: [.., ProjectionElem::Subslice { .. }],
base: _,
elem: ProjectionElem::Subslice { .. },
}),
} }
| PlaceRef { | PlaceRef {
base: _, base: _,
projection: Some(box Projection { projection: [.., ProjectionElem::Downcast(..)],
base: _,
elem: ProjectionElem::Downcast(..),
}),
} => bug!("Unexpected immutable place."), } => bug!("Unexpected immutable place."),
} }
@ -262,22 +240,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// after the field access). // after the field access).
PlaceRef { PlaceRef {
base, base,
projection: Some(box Projection { projection: [proj_base @ ..,
base: Some(box Projection { ProjectionElem::Deref,
base: Some(box Projection { ProjectionElem::Field(field, _),
base: base_proj, ProjectionElem::Deref,
elem: ProjectionElem::Deref, ],
}),
elem: ProjectionElem::Field(field, _),
}),
elem: ProjectionElem::Deref,
}),
} => { } => {
err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_label(span, format!("cannot {ACT}", ACT = act));
if let Some((span, message)) = annotate_struct_field( if let Some((span, message)) = annotate_struct_field(
self.infcx.tcx, self.infcx.tcx,
Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty, Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty,
field, field,
) { ) {
err.span_suggestion( err.span_suggestion(
@ -292,7 +265,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Suggest removing a `&mut` from the use of a mutable reference. // Suggest removing a `&mut` from the use of a mutable reference.
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} if { } if {
self.body.local_decls.get(*local).map(|local_decl| { self.body.local_decls.get(*local).map(|local_decl| {
if let ClearCrossCrate::Set( if let ClearCrossCrate::Set(
@ -328,7 +301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// variable) mutations... // variable) mutations...
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} if self.body.local_decls[*local].can_be_made_mutable() => { } if self.body.local_decls[*local].can_be_made_mutable() => {
// ... but it doesn't make sense to suggest it on // ... but it doesn't make sense to suggest it on
// variables that are `ref x`, `ref mut x`, `&self`, // variables that are `ref x`, `ref mut x`, `&self`,
@ -349,13 +322,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Also suggest adding mut for upvars // Also suggest adding mut for upvars
PlaceRef { PlaceRef {
base, base,
projection: Some(box Projection { projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
base: proj_base,
elem: ProjectionElem::Field(upvar_index, _),
}),
} => { } => {
debug_assert!(is_closure_or_generator( 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)); err.span_label(span, format!("cannot {ACT}", ACT = act));
@ -385,7 +355,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// a local variable, then just suggest the user remove it. // a local variable, then just suggest the user remove it.
PlaceRef { PlaceRef {
base: PlaceBase::Local(_), base: PlaceBase::Local(_),
projection: None, projection: [],
} if { } if {
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
snippet.starts_with("&mut ") snippet.starts_with("&mut ")
@ -400,10 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(box Projection { projection: [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
}),
} if { } if {
if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) = if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
self.body.local_decls[*local].is_user_variable self.body.local_decls[*local].is_user_variable
@ -427,10 +394,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// arbitrary base for the projection? // arbitrary base for the projection?
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(box Projection { projection: [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
}),
} if self.body.local_decls[*local].is_user_variable.is_some() => } if self.body.local_decls[*local].is_user_variable.is_some() =>
{ {
let local_decl = &self.body.local_decls[*local]; let local_decl = &self.body.local_decls[*local];
@ -510,10 +474,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { PlaceRef {
base, base,
projection: Some(box Projection { projection: [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
}),
// FIXME document what is this 1 magic number about // FIXME document what is this 1 magic number about
} if *base == PlaceBase::Local(Local::new(1)) && } if *base == PlaceBase::Local(Local::new(1)) &&
!self.upvars.is_empty() => !self.upvars.is_empty() =>
@ -527,10 +488,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { PlaceRef {
base: _, base: _,
projection: Some(box Projection { projection: [.., ProjectionElem::Deref],
base: _,
elem: ProjectionElem::Deref,
}),
} => { } => {
err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_label(span, format!("cannot {ACT}", ACT = act));

View file

@ -8,9 +8,8 @@ use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext; use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor; use rustc::mir::visit::Visitor;
use rustc::mir::{ use rustc::mir::{
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection, BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
UserTypeProjection,
}; };
use rustc::ty::fold::TypeFoldable; use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty}; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
@ -229,14 +228,11 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
match place { match place {
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} | } |
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(box Projection { projection: box [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
}),
} => { } => {
debug!( debug!(
"Recording `killed` facts for borrows of local={:?} at location={:?}", "Recording `killed` facts for borrows of local={:?} at location={:?}",
@ -261,7 +257,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(_), projection: box [.., _],
} => { } => {
// Kill conflicting borrows of the innermost local. // Kill conflicting borrows of the innermost local.
debug!( debug!(

View file

@ -274,7 +274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
if let Place { if let Place {
base: PlaceBase::Local(borrowed_local), base: PlaceBase::Local(borrowed_local),
projection: None, projection: box [],
} = place { } = place {
if body.local_decls[*borrowed_local].name.is_some() if body.local_decls[*borrowed_local].name.is_some()
&& local != *borrowed_local && local != *borrowed_local
@ -495,11 +495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Operand::Constant(c) => c.span, Operand::Constant(c) => c.span,
Operand::Copy(Place { Operand::Copy(Place {
base: PlaceBase::Local(l), base: PlaceBase::Local(l),
projection: None, projection: box [],
}) | }) |
Operand::Move(Place { Operand::Move(Place {
base: PlaceBase::Local(l), base: PlaceBase::Local(l),
projection: None, projection: box [],
}) => { }) => {
let local_decl = &self.body.local_decls[*l]; let local_decl = &self.body.local_decls[*l];
if local_decl.name.is_none() { if local_decl.name.is_none() {
@ -541,10 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// it which simplifies the termination logic. // it which simplifies the termination logic.
let mut queue = vec![location]; let mut queue = vec![location];
let mut target = if let Some(&Statement { let mut target = if let Some(&Statement {
kind: StatementKind::Assign(Place { kind: StatementKind::Assign(box(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}, _), }, _)),
.. ..
}) = stmt }) = stmt
{ {
@ -567,7 +567,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("was_captured_by_trait_object: stmt={:?}", stmt); debug!("was_captured_by_trait_object: stmt={:?}", stmt);
// The only kind of statement that we care about is assignments... // The only kind of statement that we care about is assignments...
if let StatementKind::Assign(place, box rvalue) = &stmt.kind { if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
let into = match place.local_or_deref_local() { let into = match place.local_or_deref_local() {
Some(into) => into, Some(into) => into,
None => { None => {
@ -583,11 +583,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Rvalue::Use(operand) => match operand { Rvalue::Use(operand) => match operand {
Operand::Copy(Place { Operand::Copy(Place {
base: PlaceBase::Local(from), base: PlaceBase::Local(from),
projection: None, projection: box [],
}) })
| Operand::Move(Place { | Operand::Move(Place {
base: PlaceBase::Local(from), base: PlaceBase::Local(from),
projection: None, projection: box [],
}) })
if *from == target => if *from == target =>
{ {
@ -602,11 +602,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) => match operand { ) => match operand {
Operand::Copy(Place { Operand::Copy(Place {
base: PlaceBase::Local(from), base: PlaceBase::Local(from),
projection: None, projection: box [],
}) })
| Operand::Move(Place { | Operand::Move(Place {
base: PlaceBase::Local(from), base: PlaceBase::Local(from),
projection: None, projection: box [],
}) })
if *from == target => if *from == target =>
{ {
@ -639,7 +639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let TerminatorKind::Call { if let TerminatorKind::Call {
destination: Some((Place { destination: Some((Place {
base: PlaceBase::Local(dest), base: PlaceBase::Local(dest),
projection: None, projection: box [],
}, block)), }, block)),
args, args,
.. ..
@ -653,7 +653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let found_target = args.iter().any(|arg| { let found_target = args.iter().any(|arg| {
if let Operand::Move(Place { if let Operand::Move(Place {
base: PlaceBase::Local(potential), base: PlaceBase::Local(potential),
projection: None, projection: box [],
}) = arg { }) = arg {
*potential == target *potential == target
} else { } else {

View file

@ -66,7 +66,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
self.check_activations(location); self.check_activations(location);
match statement.kind { match statement.kind {
StatementKind::Assign(ref lhs, ref rhs) => { StatementKind::Assign(box(ref lhs, ref rhs)) => {
self.consume_rvalue( self.consume_rvalue(
location, location,
rhs, rhs,

View file

@ -421,107 +421,104 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
) -> PlaceTy<'tcx> { ) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place); debug!("sanitize_place: {:?}", place);
place.iterate(|place_base, place_projection| { let mut place_ty = match &place.base {
let mut place_ty = match place_base { PlaceBase::Local(index) =>
PlaceBase::Local(index) => PlaceTy::from_ty(self.body.local_decls[*index].ty),
PlaceTy::from_ty(self.body.local_decls[*index].ty), PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
PlaceBase::Static(box Static { kind, ty: sty, def_id }) => { let sty = self.sanitize_type(place, sty);
let sty = self.sanitize_type(place, sty); let check_err =
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>, place: &Place<'tcx>,
place: &Place<'tcx>, ty,
ty, sty| {
sty| { if let Err(terr) = verifier.cx.eq_types(
if let Err(terr) = verifier.cx.eq_types( sty,
sty, ty,
ty, location.to_locations(),
location.to_locations(), ConstraintCategory::Boring,
ConstraintCategory::Boring, ) {
) { span_mirbug!(
span_mirbug!( verifier,
verifier, place,
place, "bad promoted type ({:?}: {:?}): {:?}",
"bad promoted type ({:?}: {:?}): {:?}", ty,
ty, sty,
sty, terr
terr );
);
};
}; };
match kind { };
StaticKind::Promoted(promoted, _) => { match kind {
if !self.errors_reported { StaticKind::Promoted(promoted, _) => {
let promoted_body = &self.promoted[*promoted]; if !self.errors_reported {
self.sanitize_promoted(promoted_body, location); let promoted_body = &self.promoted[*promoted];
self.sanitize_promoted(promoted_body, location);
let promoted_ty = promoted_body.return_ty(); let promoted_ty = promoted_body.return_ty();
check_err(self, place, promoted_ty, sty); check_err(self, place, promoted_ty, sty);
}
}
StaticKind::Static => {
let ty = self.tcx().type_of(*def_id);
let ty = self.cx.normalize(ty, location);
check_err(self, place, ty, sty);
} }
} }
PlaceTy::from_ty(sty) StaticKind::Static => {
} let ty = self.tcx().type_of(*def_id);
}; let ty = self.cx.normalize(ty, location);
// FIXME use place_projection.is_empty() when is available check_err(self, place, ty, sty);
if place.projection.is_none() { }
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { }
let is_promoted = match place { PlaceTy::from_ty(sty)
Place { }
base: PlaceBase::Static(box Static { };
kind: StaticKind::Promoted(..),
.. if place.projection.is_empty() {
}), if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
projection: None, let is_promoted = match place {
} => true, Place {
_ => false, 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 { // To have a `Copy` operand, the type `T` of the
let tcx = self.tcx(); // value must be `Copy`. Note that we prove that `T: Copy`,
let trait_ref = ty::TraitRef { // rather than using the `is_copy_modulo_regions`
def_id: tcx.lang_items().copy_trait().unwrap(), // test. This is important because
substs: tcx.mk_substs_trait(place_ty.ty, &[]), // `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.,
// In order to have a Copy operand, the type T of the // #29149). Note that we decide to use `Copy` before knowing
// value must be Copy. Note that we prove that T: Copy, // whether the bounds fully apply: in effect, the rule is
// rather than using the `is_copy_modulo_regions` // that if a value of some type could implement `Copy`, then
// test. This is important because // it must.
// `is_copy_modulo_regions` ignores the resulting region self.cx.prove_trait_ref(
// obligations and assumes they pass. This can result in trait_ref,
// bounds from Copy impls being unsoundly ignored (e.g., location.to_locations(),
// #29149). Note that we decide to use Copy before knowing ConstraintCategory::CopyBound,
// 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 { for elem in place.projection.iter() {
if place_ty.variant_index.is_none() { if place_ty.variant_index.is_none() {
if place_ty.ty.references_error() { if place_ty.ty.references_error() {
assert!(self.errors_reported); assert!(self.errors_reported);
return PlaceTy::from_ty(self.tcx().types.err); 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) { fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
@ -1346,7 +1343,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!("check_stmt: {:?}", stmt); debug!("check_stmt: {:?}", stmt);
let tcx = self.tcx(); let tcx = self.tcx();
match stmt.kind { match stmt.kind {
StatementKind::Assign(ref place, ref rv) => { StatementKind::Assign(box(ref place, ref rv)) => {
// Assignments to temporaries are not "interesting"; // Assignments to temporaries are not "interesting";
// they are not caused by the user, but rather artifacts // they are not caused by the user, but rather artifacts
// of lowering. Assignments to other sorts of places *are* interesting // of lowering. Assignments to other sorts of places *are* interesting
@ -1354,7 +1351,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let category = match *place { let category = match *place {
Place { Place {
base: PlaceBase::Local(RETURN_PLACE), base: PlaceBase::Local(RETURN_PLACE),
projection: None, projection: box [],
} => if let BorrowCheckContext { } => if let BorrowCheckContext {
universal_regions: universal_regions:
UniversalRegions { UniversalRegions {
@ -1373,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}, },
Place { Place {
base: PlaceBase::Local(l), base: PlaceBase::Local(l),
projection: None, projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => { } if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring ConstraintCategory::Boring
} }
@ -1453,7 +1450,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
); );
}; };
} }
StatementKind::AscribeUserType(ref place, variance, box ref projection) => { StatementKind::AscribeUserType(box(ref place, ref projection), variance) => {
let place_ty = place.ty(body, tcx).ty; let place_ty = place.ty(body, tcx).ty;
if let Err(terr) = self.relate_type_and_user_type( if let Err(terr) = self.relate_type_and_user_type(
place_ty, place_ty,
@ -1660,7 +1657,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let category = match *dest { let category = match *dest {
Place { Place {
base: PlaceBase::Local(RETURN_PLACE), base: PlaceBase::Local(RETURN_PLACE),
projection: None, projection: box [],
} => { } => {
if let BorrowCheckContext { if let BorrowCheckContext {
universal_regions: universal_regions:
@ -1682,7 +1679,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
Place { Place {
base: PlaceBase::Local(l), base: PlaceBase::Local(l),
projection: None, projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => { } if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring ConstraintCategory::Boring
} }
@ -2416,19 +2413,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// *p`, where the `p` has type `&'b mut Foo`, for example, we // *p`, where the `p` has type `&'b mut Foo`, for example, we
// need to ensure that `'b: 'a`. // need to ensure that `'b: 'a`.
let mut borrowed_projection = &borrowed_place.projection;
debug!( debug!(
"add_reborrow_constraint({:?}, {:?}, {:?})", "add_reborrow_constraint({:?}, {:?}, {:?})",
location, borrow_region, borrowed_place location, borrow_region, borrowed_place
); );
while let Some(box proj) = borrowed_projection { for (i, elem) in borrowed_place.projection.iter().enumerate().rev() {
debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection); debug!("add_reborrow_constraint - iteration {:?}", elem);
let proj_base = &borrowed_place.projection[..i];
match proj.elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let tcx = self.infcx.tcx; 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); debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.sty { match base_ty.sty {
@ -2490,10 +2486,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// other field access // other field access
} }
} }
// The "propagate" case. We need to check that our base is valid
// for the borrow's lifetime.
borrowed_projection = &proj.base;
} }
} }

View file

@ -25,55 +25,54 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
body: &Body<'tcx>, body: &Body<'tcx>,
locals_state_at_exit: &LocalsStateAtExit, locals_state_at_exit: &LocalsStateAtExit,
) -> bool { ) -> bool {
self.iterate(|place_base, place_projection| { let ignore = match self.base {
let ignore = match place_base { // If a local variable is immutable, then we only need to track borrows to guard
// If a local variable is immutable, then we only need to track borrows to guard // against two kinds of errors:
// against two kinds of errors: // * The variable being dropped while still borrowed (e.g., because the fn returns
// * The variable being dropped while still borrowed (e.g., because the fn returns // a reference to a local variable)
// a reference to a local variable) // * The variable being moved while still borrowed
// * The variable being moved while still borrowed //
// // In particular, the variable cannot be mutated -- the "access checks" will fail --
// In particular, the variable cannot be mutated -- the "access checks" will fail -- // so we don't have to worry about mutation while borrowed.
// so we don't have to worry about mutation while borrowed. PlaceBase::Local(index) => {
PlaceBase::Local(index) => { match locals_state_at_exit {
match locals_state_at_exit { LocalsStateAtExit::AllAreInvalidated => false,
LocalsStateAtExit::AllAreInvalidated => false, LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => { let ignore = !has_storage_dead_or_moved.contains(index) &&
let ignore = !has_storage_dead_or_moved.contains(*index) && body.local_decls[index].mutability == Mutability::Not;
body.local_decls[*index].mutability == Mutability::Not; debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
debug!("ignore_borrow: local {:?} => {:?}", index, ignore); 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)
}
};
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,
_ => {}
} }
} }
} }
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
false,
PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
tcx.is_mutable_static(def_id)
}
};
ignore 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;
if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = ty.sty {
// For both derefs of raw pointers and `&T`
// references, the original path is `Copy` and
// therefore not significant. In particular,
// 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.
return true;
}
}
}
ignore
} }
} }

View file

@ -3,8 +3,7 @@ use crate::borrow_check::Overlap;
use crate::borrow_check::{Deep, Shallow, AccessDepth}; use crate::borrow_check::{Deep, Shallow, AccessDepth};
use rustc::hir; use rustc::hir;
use rustc::mir::{ use rustc::mir::{
Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter, Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
StaticKind,
}; };
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use std::cmp::max; use std::cmp::max;
@ -67,39 +66,35 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
// it's so common that it's a speed win to check for it first. // it's so common that it's a speed win to check for it first.
if let Place { if let Place {
base: PlaceBase::Local(l1), base: PlaceBase::Local(l1),
projection: None, projection: box [],
} = borrow_place { } = borrow_place {
if let PlaceRef { if let PlaceRef {
base: PlaceBase::Local(l2), base: PlaceBase::Local(l2),
projection: None, projection: [],
} = access_place { } = access_place {
return l1 == l2; return l1 == l2;
} }
} }
borrow_place.iterate(|borrow_base, borrow_projections| { place_components_conflict(
access_place.iterate(|access_base, access_projections| { tcx,
place_components_conflict( param_env,
tcx, body,
param_env, borrow_place,
body, borrow_kind,
(borrow_base, borrow_projections), access_place,
borrow_kind, access,
(access_base, access_projections), bias,
access, )
bias,
)
})
})
} }
fn place_components_conflict<'tcx>( fn place_components_conflict<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), borrow_place: &Place<'tcx>,
borrow_kind: BorrowKind, borrow_kind: BorrowKind,
access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>), access_place: PlaceRef<'_, 'tcx>,
access: AccessDepth, access: AccessDepth,
bias: PlaceConflictBias, bias: PlaceConflictBias,
) -> bool { ) -> bool {
@ -145,8 +140,8 @@ fn place_components_conflict<'tcx>(
// and either equal or disjoint. // and either equal or disjoint.
// - If we did run out of access, the borrow can access a part of it. // - If we did run out of access, the borrow can access a part of it.
let borrow_base = borrow_projections.0; let borrow_base = &borrow_place.base;
let access_base = access_projections.0; let access_base = access_place.base;
match place_base_conflict(tcx, param_env, borrow_base, access_base) { match place_base_conflict(tcx, param_env, borrow_base, access_base) {
Overlap::Arbitrary => { Overlap::Arbitrary => {
@ -163,147 +158,157 @@ fn place_components_conflict<'tcx>(
} }
} }
let mut borrow_projections = borrow_projections.1; // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
let mut access_projections = access_projections.1; 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];
loop { debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
// 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);
if let Some(access_c) = access_projections.next() { // Borrow and access path both have more components.
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); //
// Examples:
// Borrow and access path both have more components. //
// - 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.
// //
// Examples: // 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).
// //
// - borrow of `a.(...)`, access to `a.(...)` // We could try to do some things here - e.g., count
// - borrow of `a.(...)`, access to `b.(...)` // dereferences - but that's probably not a good
// // idea, at least for now, so just give up and
// Here we only see the components we have checked so // report a conflict. This is unsafe code anyway so
// far (in our examples, just the first component). We // the user could always use raw pointers.
// check whether the components being borrowed vs debug!("borrow_conflicts_with_place: arbitrary -> conflict");
// 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 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;
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::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`.
}
}
}
} 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; 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 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;
}
(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::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`.
}
}
}
}
// 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 // Given that the bases of `elem1` and `elem2` are always either equal
@ -381,11 +386,12 @@ fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
pi1_base: &PlaceBase<'tcx>, pi1_base: &PlaceBase<'tcx>,
pi1: &Projection<'tcx>, pi1_proj_base: &[PlaceElem<'tcx>],
pi2: &Projection<'tcx>, pi1_elem: &PlaceElem<'tcx>,
pi2_elem: &PlaceElem<'tcx>,
bias: PlaceConflictBias, bias: PlaceConflictBias,
) -> Overlap { ) -> Overlap {
match (&pi1.elem, &pi2.elem) { match (pi1_elem, pi2_elem) {
(ProjectionElem::Deref, ProjectionElem::Deref) => { (ProjectionElem::Deref, ProjectionElem::Deref) => {
// derefs (e.g., `*x` vs. `*x`) - recur. // derefs (e.g., `*x` vs. `*x`) - recur.
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
@ -397,7 +403,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint Overlap::EqualOrDisjoint
} else { } 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 { match ty.sty {
ty::Adt(def, _) if def.is_union() => { ty::Adt(def, _) if def.is_union() => {
// Different fields of a union, we are basically stuck. // Different fields of a union, we are basically stuck.
@ -493,7 +499,7 @@ fn place_projection_conflict<'tcx>(
// element (like -1 in Python) and `min_length` the first. // element (like -1 in Python) and `min_length` the first.
// Therefore, `min_length - offset_from_end` gives the minimal possible // Therefore, `min_length - offset_from_end` gives the minimal possible
// offset from the beginning // 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"); debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
Overlap::EqualOrDisjoint Overlap::EqualOrDisjoint
} else { } else {
@ -538,8 +544,8 @@ fn place_projection_conflict<'tcx>(
| (ProjectionElem::Subslice { .. }, _) | (ProjectionElem::Subslice { .. }, _)
| (ProjectionElem::Downcast(..), _) => bug!( | (ProjectionElem::Downcast(..), _) => bug!(
"mismatched projections in place_element_conflict: {:?} and {:?}", "mismatched projections in place_element_conflict: {:?} and {:?}",
pi1, pi1_elem,
pi2 pi2_elem
), ),
} }
} }

View file

@ -19,17 +19,9 @@ pub trait IsPrefixOf<'cx, 'tcx> {
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> { impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool { fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
let mut cursor = other.projection; self.base == other.base
loop { && self.projection.len() <= other.projection.len()
if self.projection == cursor { && self.projection == &other.projection[..self.projection.len()]
return self.base == other.base;
}
match cursor {
None => return false,
Some(proj) => cursor = &proj.base,
}
}
} }
} }
@ -81,112 +73,113 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
// downcasts here, but may return a base of a downcast). // downcasts here, but may return a base of a downcast).
'cursor: loop { 'cursor: loop {
let proj = match &cursor { match &cursor {
PlaceRef { PlaceRef {
base: PlaceBase::Local(_), base: PlaceBase::Local(_),
projection: None, projection: [],
} }
| // search yielded this leaf | // search yielded this leaf
PlaceRef { PlaceRef {
base: PlaceBase::Static(_), base: PlaceBase::Static(_),
projection: None, projection: [],
} => { } => {
self.next = None; self.next = None;
return Some(cursor); return Some(cursor);
} }
PlaceRef { PlaceRef {
base: _, base: _,
projection: Some(proj), projection: [proj_base @ .., elem],
} => proj, } => {
}; 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)
}
}
match proj.elem { assert_eq!(*elem, ProjectionElem::Deref);
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!
}
}
match self.kind { assert_eq!(self.kind, PrefixSet::Supporting);
PrefixSet::Shallow => { // Supporting prefixes: strip away fields and
// shallow prefixes are found by stripping away // derefs, except we stop at the deref of a shared
// fields, but stop at *any* dereference. // reference.
// 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); let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty;
// supporting prefixes: strip away fields and match ty.sty {
// derefs, except we stop at the deref of a shared ty::RawPtr(_) |
// reference. ty::Ref(
_, /*rgn*/
_, /*ty*/
hir::MutImmutable
) => {
// don't continue traversing over derefs of raw pointers or shared
// borrows.
self.next = None;
return Some(cursor);
}
let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty; ty::Ref(
match ty.sty { _, /*rgn*/
ty::RawPtr(_) | _, /*ty*/
ty::Ref( hir::MutMutable,
_, /*rgn*/ ) => {
_, /*ty*/ self.next = Some(PlaceRef {
hir::MutImmutable base: cursor.base,
) => { projection: proj_base,
// don't continue traversing over derefs of raw pointers or shared borrows. });
self.next = None; return Some(cursor);
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."),
}
} }
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."),
} }
} }
} }

View file

@ -89,7 +89,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
_location: Location, _location: Location,
) { ) {
match &statement.kind { match &statement.kind {
StatementKind::Assign(into, _) => { StatementKind::Assign(box(into, _)) => {
if let PlaceBase::Local(local) = into.base { if let PlaceBase::Local(local) = into.base {
debug!( debug!(
"visit_statement: statement={:?} local={:?} \ "visit_statement: statement={:?} local={:?} \
@ -120,7 +120,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
); );
if let Place { if let Place {
base: PlaceBase::Local(user_local), base: PlaceBase::Local(user_local),
projection: None, projection: box [],
} = path.place { } = path.place {
self.mbcx.used_mut.insert(user_local); self.mbcx.used_mut.insert(user_local);
} }

View file

@ -37,7 +37,7 @@ impl<'tcx> CFG<'tcx> {
rvalue: Rvalue<'tcx>) { rvalue: Rvalue<'tcx>) {
self.push(block, Statement { self.push(block, Statement {
source_info, source_info,
kind: StatementKind::Assign(place.clone(), box rvalue) kind: StatementKind::Assign(box(place.clone(), rvalue))
}); });
} }

View file

@ -129,7 +129,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
kind: StaticKind::Static, kind: StaticKind::Static,
def_id: id, def_id: id,
})), })),
projection: None, projection: box [],
}), }),
ExprKind::PlaceTypeAscription { source, user_ty } => { ExprKind::PlaceTypeAscription { source, user_ty } => {
@ -147,9 +147,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Statement { Statement {
source_info, source_info,
kind: StatementKind::AscribeUserType( kind: StatementKind::AscribeUserType(
place.clone(), box(
place.clone(),
UserTypeProjection { base: annotation_index, projs: vec![], }
),
Variance::Invariant, Variance::Invariant,
box UserTypeProjection { base: annotation_index, projs: vec![], },
), ),
}, },
); );
@ -174,9 +176,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Statement { Statement {
source_info, source_info,
kind: StatementKind::AscribeUserType( kind: StatementKind::AscribeUserType(
Place::from(temp.clone()), box(
Place::from(temp.clone()),
UserTypeProjection { base: annotation_index, projs: vec![], },
),
Variance::Invariant, Variance::Invariant,
box UserTypeProjection { base: annotation_index, projs: vec![], },
), ),
}, },
); );

View file

@ -500,14 +500,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mutability = match arg_place { let mutability = match arg_place {
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} => this.local_decls[local].mutability, } => this.local_decls[local].mutability,
Place { Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: Some(box Projection { projection: box [ProjectionElem::Deref],
base: None,
elem: ProjectionElem::Deref,
})
} => { } => {
debug_assert!( debug_assert!(
this.local_decls[local].is_ref_for_guard(), this.local_decls[local].is_ref_for_guard(),
@ -517,24 +514,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
Place { Place {
ref base, ref base,
projection: Some(box Projection { projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
base: ref base_proj,
elem: ProjectionElem::Field(upvar_index, _),
}),
} }
| Place { | Place {
ref base, ref base,
projection: Some(box Projection { projection: box [
base: Some(box Projection { ref proj_base @ ..,
base: ref base_proj, ProjectionElem::Field(upvar_index, _),
elem: ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref
}), ],
elem: ProjectionElem::Deref,
}),
} => { } => {
let place = PlaceRef { let place = PlaceRef {
base, base,
projection: base_proj, projection: proj_base,
}; };
// Not projected from the implicit `self` in a closure. // Not projected from the implicit `self` in a closure.

View file

@ -301,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Create a "fake" temporary variable so that we check that the // Create a "fake" temporary variable so that we check that the
// value is Sized. Usually, this is caught in type checking, but // value is Sized. Usually, this is caught in type checking, but
// in the case of box expr there is no such check. // in the case of box expr there is no such check.
if destination.projection.is_some() { if !destination.projection.is_empty() {
this.local_decls this.local_decls
.push(LocalDecl::new_temp(expr.ty, expr.span)); .push(LocalDecl::new_temp(expr.ty, expr.span));
} }

View file

@ -135,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
source_info, source_info,
kind: StatementKind::FakeRead( kind: StatementKind::FakeRead(
FakeReadCause::ForMatchedPlace, FakeReadCause::ForMatchedPlace,
scrutinee_place.clone(), box(scrutinee_place.clone()),
), ),
}); });
@ -320,7 +320,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block, block,
Statement { Statement {
source_info, source_info,
kind: StatementKind::FakeRead(FakeReadCause::ForLet, place), kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)),
}, },
); );
@ -362,12 +362,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block, block,
Statement { Statement {
source_info: pattern_source_info, source_info: pattern_source_info,
kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()), kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())),
}, },
); );
let ty_source_info = self.source_info(user_ty_span); let ty_source_info = self.source_info(user_ty_span);
let user_ty = box pat_ascription_ty.user_ty( let user_ty = pat_ascription_ty.user_ty(
&mut self.canonical_user_type_annotations, &mut self.canonical_user_type_annotations,
place.ty(&self.local_decls, self.hir.tcx()).ty, place.ty(&self.local_decls, self.hir.tcx()).ty,
ty_source_info.span, ty_source_info.span,
@ -377,7 +377,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Statement { Statement {
source_info: ty_source_info, source_info: ty_source_info,
kind: StatementKind::AscribeUserType( kind: StatementKind::AscribeUserType(
place, box(
place,
user_ty,
),
// We always use invariant as the variance here. This is because the // We always use invariant as the variance here. This is because the
// variance field from the ascription refers to the variance to use // variance field from the ascription refers to the variance to use
// when applying the type to the value being matched, but this // when applying the type to the value being matched, but this
@ -393,7 +396,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// contrast, is intended to be used to relate `T` to the type of // contrast, is intended to be used to relate `T` to the type of
// `<expr>`. // `<expr>`.
ty::Variance::Invariant, ty::Variance::Invariant,
user_ty,
), ),
}, },
); );
@ -942,16 +944,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
for Binding { source, .. } for Binding { source, .. }
in matched_candidates.iter().flat_map(|candidate| &candidate.bindings) in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
{ {
let mut cursor = &source.projection; if let Some(i) =
while let Some(box Projection { base, elem }) = cursor { source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
cursor = base; {
if let ProjectionElem::Deref = elem { let proj_base = &source.projection[..i];
fake_borrows.insert(Place {
base: source.base.clone(), fake_borrows.insert(Place {
projection: cursor.clone(), base: source.base.clone(),
}); projection: proj_base.to_vec().into_boxed_slice(),
break; });
}
} }
} }
} }
@ -1295,18 +1296,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Insert a Shallow borrow of the prefixes of any fake borrows. // Insert a Shallow borrow of the prefixes of any fake borrows.
for place in fake_borrows for place in fake_borrows
{ {
let mut prefix_cursor = &place.projection; for (i, elem) in place.projection.iter().enumerate().rev() {
while let Some(box Projection { base, elem }) = prefix_cursor { let proj_base = &place.projection[..i];
if let ProjectionElem::Deref = elem { if let ProjectionElem::Deref = elem {
// Insert a shallow borrow after a deref. For other // Insert a shallow borrow after a deref. For other
// projections the borrow of prefix_cursor will // projections the borrow of prefix_cursor will
// conflict with any mutation of base. // conflict with any mutation of base.
all_fake_borrows.push(PlaceRef { all_fake_borrows.push(PlaceRef {
base: &place.base, base: &place.base,
projection: base, projection: proj_base,
}); });
} }
prefix_cursor = base;
} }
all_fake_borrows.push(place.as_ref()); all_fake_borrows.push(place.as_ref());
@ -1489,7 +1490,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
BorrowKind::Shallow, BorrowKind::Shallow,
Place { Place {
base: place.base.clone(), base: place.base.clone(),
projection: place.projection.clone(), projection: place.projection.to_vec().into_boxed_slice(),
}, },
); );
self.cfg.push_assign( self.cfg.push_assign(
@ -1520,7 +1521,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
source_info: guard_end, source_info: guard_end,
kind: StatementKind::FakeRead( kind: StatementKind::FakeRead(
FakeReadCause::ForMatchGuard, FakeReadCause::ForMatchGuard,
Place::from(temp), box(Place::from(temp)),
), ),
}); });
} }
@ -1570,7 +1571,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
post_guard_block, post_guard_block,
Statement { Statement {
source_info: guard_end, source_info: guard_end,
kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place), kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)),
}, },
); );
} }
@ -1603,7 +1604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ascription.user_ty, ascription.user_ty,
); );
let user_ty = box ascription.user_ty.clone().user_ty( let user_ty = ascription.user_ty.clone().user_ty(
&mut self.canonical_user_type_annotations, &mut self.canonical_user_type_annotations,
ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
source_info.span source_info.span
@ -1613,9 +1614,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Statement { Statement {
source_info, source_info,
kind: StatementKind::AscribeUserType( kind: StatementKind::AscribeUserType(
ascription.source.clone(), box(
ascription.source.clone(),
user_ty,
),
ascription.variance, ascription.variance,
user_ty,
), ),
}, },
); );

View file

@ -609,7 +609,7 @@ where
unpack!(block = builder.in_breakable_scope( unpack!(block = builder.in_breakable_scope(
None, None,
START_BLOCK, START_BLOCK,
Place::RETURN_PLACE, Place::return_place(),
|builder| { |builder| {
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
builder.args_and_body(block, &arguments, arg_scope, &body.value) builder.args_and_body(block, &arguments, arg_scope, &body.value)
@ -670,7 +670,7 @@ fn construct_const<'a, 'tcx>(
let mut block = START_BLOCK; let mut block = START_BLOCK;
let ast_expr = &tcx.hir().body(body_id).value; let ast_expr = &tcx.hir().body(body_id).value;
let expr = builder.hir.mirror(ast_expr); 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); let source_info = builder.source_info(span);
builder.cfg.terminate(block, source_info, TerminatorKind::Return); builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
let body = self.hir.mirror(ast_body); 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( fn set_correct_source_scope_for_arg(

View file

@ -314,7 +314,7 @@ impl<'tcx> Scopes<'tcx> {
match target { match target {
BreakableTarget::Return => { BreakableTarget::Return => {
let scope = &self.breakable_scopes[0]; 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"); span_bug!(span, "`return` in item with no return scope");
} }
(scope.break_block, scope.region_scope, Some(scope.break_destination.clone())) (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
@ -853,11 +853,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
_ if self.local_scope().is_none() => (), _ if self.local_scope().is_none() => (),
Operand::Copy(Place { Operand::Copy(Place {
base: PlaceBase::Local(cond_temp), base: PlaceBase::Local(cond_temp),
projection: None, projection: box [],
}) })
| Operand::Move(Place { | Operand::Move(Place {
base: PlaceBase::Local(cond_temp), base: PlaceBase::Local(cond_temp),
projection: None, projection: box [],
}) => { }) => {
// Manually drop the condition on both branches. // Manually drop the condition on both branches.
let top_scope = self.scopes.scopes.last_mut().unwrap(); let top_scope = self.scopes.scopes.last_mut().unwrap();

View file

@ -10,19 +10,17 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
path: MovePathIndex, path: MovePathIndex,
mut cond: F) mut cond: F)
-> Option<MovePathIndex> -> 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; let mut next_child = move_data.move_paths[path].first_child;
while let Some(child_index) = next_child { while let Some(child_index) = next_child {
match move_data.move_paths[child_index].place.projection { let move_path_children = &move_data.move_paths[child_index];
Some(ref proj) => { if let Some(elem) = move_path_children.place.projection.last() {
if cond(proj) { if cond(elem) {
return Some(child_index) return Some(child_index)
}
} }
_ => {}
} }
next_child = move_data.move_paths[child_index].next_sibling; next_child = move_path_children.next_sibling;
} }
None None

View file

@ -208,7 +208,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// If the borrowed place is a local with no projections, all other borrows of this // 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 // local must conflict. This is purely an optimization so we don't have to call
// `places_conflict` for every borrow. // `places_conflict` for every borrow.
if place.projection.is_none() { if place.projection.is_empty() {
trans.kill_all(other_borrows_of_local); trans.kill_all(other_borrows_of_local);
return; return;
} }
@ -268,8 +268,8 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
debug!("Borrows::statement_effect: stmt={:?}", stmt); debug!("Borrows::statement_effect: stmt={:?}", stmt);
match stmt.kind { match stmt.kind {
mir::StatementKind::Assign(ref lhs, ref rhs) => { mir::StatementKind::Assign(box(ref lhs, ref rhs)) => {
if let mir::Rvalue::Ref(_, _, ref place) = **rhs { if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
if place.ignore_borrow( if place.ignore_borrow(
self.tcx, self.tcx,
self.body, self.body,

View file

@ -119,8 +119,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
match stmt.kind { match stmt.kind {
StatementKind::StorageLive(l) => sets.gen(l), StatementKind::StorageLive(l) => sets.gen(l),
StatementKind::StorageDead(l) => sets.kill(l), StatementKind::StorageDead(l) => sets.kill(l),
StatementKind::Assign(ref place, _) StatementKind::Assign(box(ref place, _))
| StatementKind::SetDiscriminant { ref place, .. } => { | StatementKind::SetDiscriminant { box ref place, .. } => {
if let PlaceBase::Local(local) = place.base { if let PlaceBase::Local(local) = place.base {
sets.gen(local); sets.gen(local);
} }

View file

@ -94,72 +94,74 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
/// Maybe we should have separate "borrowck" and "moveck" modes. /// Maybe we should have separate "borrowck" and "moveck" modes.
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> { fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
debug!("lookup({:?})", place); debug!("lookup({:?})", place);
place.iterate(|place_base, place_projection| { let mut base = match place.base {
let mut base = match place_base { PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local], PlaceBase::Static(..) => {
PlaceBase::Static(..) => { return Err(MoveError::cannot_move_out_of(self.loc, Static));
return Err(MoveError::cannot_move_out_of(self.loc, Static)); }
};
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() => {
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,
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
));
}
_ => {
// FIXME: still badly broken
}
},
_ => {}
}; };
for proj in place_projection { let proj = &place.projection[..i+1];
let body = self.builder.body; base = match self
let tcx = self.builder.tcx; .builder
let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty; .data
match place_ty.sty { .rev_lookup
ty::Ref(..) | ty::RawPtr(..) => { .projections
return Err(MoveError::cannot_move_out_of( .entry((base, elem.lift()))
self.loc,
BorrowedContent {
target_place: Place {
base: place_base.clone(),
projection: Some(Box::new(proj.clone())),
},
},
));
}
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
return Err(MoveError::cannot_move_out_of(
self.loc,
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 proj.elem {
ProjectionElem::Index(..) => true,
_ => false,
},
},
));
}
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()))
{ {
Entry::Occupied(ent) => *ent.get(), Entry::Occupied(ent) => *ent.get(),
Entry::Vacant(ent) => { Entry::Vacant(ent) => {
@ -169,18 +171,17 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
&mut self.builder.data.init_path_map, &mut self.builder.data.init_path_map,
Some(base), Some(base),
Place { Place {
base: place_base.clone(), base: place.base.clone(),
projection: Some(Box::new(proj.clone())), projection: proj.to_vec().into_boxed_slice(),
}, },
); );
ent.insert(path); ent.insert(path);
path path
} }
}; };
} }
Ok(base) Ok(base)
})
} }
fn create_move_path(&mut self, place: &Place<'tcx>) { fn create_move_path(&mut self, place: &Place<'tcx>) {
@ -267,7 +268,7 @@ struct Gatherer<'b, 'a, 'tcx> {
impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
fn gather_statement(&mut self, stmt: &Statement<'tcx>) { fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
match stmt.kind { match stmt.kind {
StatementKind::Assign(ref place, ref rval) => { StatementKind::Assign(box(ref place, ref rval)) => {
self.create_move_path(place); self.create_move_path(place);
if let RvalueInitializationState::Shallow = rval.initialization_state() { if let RvalueInitializationState::Shallow = rval.initialization_state() {
// Box starts out uninitialized - need to create a separate // Box starts out uninitialized - need to create a separate
@ -355,7 +356,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| TerminatorKind::Unreachable => {} | TerminatorKind::Unreachable => {}
TerminatorKind::Return => { TerminatorKind::Return => {
self.gather_move(&Place::RETURN_PLACE); self.gather_move(&Place::return_place());
} }
TerminatorKind::Assert { ref cond, .. } => { TerminatorKind::Assert { ref cond, .. } => {
@ -435,9 +436,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// Check if we are assigning into a field of a union, if so, lookup the place // 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. // of the union so it is marked as initialized again.
if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) = if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
place.projection
{
if let ty::Adt(def, _) = if let ty::Adt(def, _) =
Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
{ {

View file

@ -245,23 +245,21 @@ impl MovePathLookup {
// alternative will *not* create a MovePath on the fly for an // alternative will *not* create a MovePath on the fly for an
// unknown place, but will rather return the nearest available // unknown place, but will rather return the nearest available
// parent. // parent.
pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult { pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
place_ref.iterate(|place_base, place_projection| { let mut result = match place.base {
let mut result = match place_base { PlaceBase::Local(local) => self.locals[*local],
PlaceBase::Local(local) => self.locals[*local], PlaceBase::Static(..) => return LookupResult::Parent(None),
PlaceBase::Static(..) => return LookupResult::Parent(None), };
};
for proj in place_projection { for elem in place.projection.iter() {
if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) { if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
result = subpath; result = subpath;
} else { } else {
return LookupResult::Parent(Some(result)); return LookupResult::Parent(Some(result));
}
} }
}
LookupResult::Exact(result) LookupResult::Exact(result)
})
} }
pub fn find_local(&self, local: Local) -> MovePathIndex { pub fn find_local(&self, local: Local) -> MovePathIndex {
@ -329,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> { pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
loop { loop {
let path = &self.move_paths[mpi]; 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); return Some(l);
} }
if let Some(parent) = path.parent { if let Some(parent) = path.parent {

View file

@ -472,39 +472,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// avoid allocations. // avoid allocations.
pub(super) fn eval_place_to_op( pub(super) fn eval_place_to_op(
&self, &self,
mir_place: &mir::Place<'tcx>, place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>, layout: Option<TyLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::PlaceBase; use rustc::mir::PlaceBase;
mir_place.iterate(|place_base, place_projection| { let mut op = match &place.base {
let mut op = match place_base { PlaceBase::Local(mir::RETURN_PLACE) =>
PlaceBase::Local(mir::RETURN_PLACE) => throw_unsup!(ReadFromReturnPointer),
throw_unsup!(ReadFromReturnPointer), PlaceBase::Local(local) => {
PlaceBase::Local(local) => { // Do not use the layout passed in as argument if the base we are looking at
// Do not use the layout passed in as argument if the base we are looking at // here is not the entire place.
// here is not the entire place. // FIXME use place_projection.is_empty() when is available
// FIXME use place_projection.is_empty() when is available let layout = if place.projection.is_empty() {
let layout = if mir_place.projection.is_none() { layout
layout } else {
} else { None
None };
};
self.access_local(self.frame(), *local, layout)? self.access_local(self.frame(), *local, layout)?
}
PlaceBase::Static(place_static) => {
self.eval_static_to_mplace(place_static)?.into()
}
};
for proj in place_projection {
op = self.operand_projection(op, &proj.elem)?
} }
PlaceBase::Static(place_static) => {
self.eval_static_to_mplace(&place_static)?.into()
}
};
trace!("eval_place_to_op: got {:?}", *op); for elem in place.projection.iter() {
Ok(op) 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. /// Evaluate the operand, returning a place where you can then find the data.

View file

@ -629,45 +629,43 @@ where
/// place; for reading, a more efficient alternative is `eval_place_for_read`. /// place; for reading, a more efficient alternative is `eval_place_for_read`.
pub fn eval_place( pub fn eval_place(
&mut self, &mut self,
mir_place: &mir::Place<'tcx>, place: &mir::Place<'tcx>,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::PlaceBase; use rustc::mir::PlaceBase;
mir_place.iterate(|place_base, place_projection| { let mut place_ty = match &place.base {
let mut place = match place_base { PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { Some(return_place) => {
Some(return_place) => { // We use our layout to verify our assumption; caller will validate
// We use our layout to verify our assumption; caller will validate // their layout on return.
// their layout on return. PlaceTy {
PlaceTy { place: *return_place,
place: *return_place, layout: self.layout_of(
layout: self.layout_of( self.subst_from_frame_and_normalize_erasing_regions(
self.subst_from_frame_and_normalize_erasing_regions( self.frame().body.return_ty()
self.frame().body.return_ty() )
) )?,
)?,
}
} }
None => throw_unsup!(InvalidNullPointerUsage), }
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::Local(local) => PlaceTy { layout: self.layout_of_local(self.frame(), *local, None)?,
// This works even for dead/uninitialized locals; we check further when writing },
place: Place::Local { PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
frame: self.cur_frame(), };
local: *local,
},
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 { for elem in place.projection.iter() {
place = self.place_projection(place, &proj.elem)? place_ty = self.place_projection(place_ty, elem)?
} }
self.dump_place(place.place); self.dump_place(place_ty.place);
Ok(place) Ok(place_ty)
})
} }
/// Write a scalar to a place /// Write a scalar to a place

View file

@ -82,7 +82,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.memory.tcx.span = stmt.source_info.span; self.memory.tcx.span = stmt.source_info.span;
match stmt.kind { match stmt.kind {
Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?, Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,
SetDiscriminant { SetDiscriminant {
ref place, ref place,

View file

@ -391,7 +391,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Don't forget to check the return type! // Don't forget to check the return type!
if let Some(caller_ret) = dest { if let Some(caller_ret) = dest {
let callee_ret = self.eval_place( let callee_ret = self.eval_place(
&mir::Place::RETURN_PLACE &mir::Place::return_place()
)?; )?;
if !Self::check_argument_compat( if !Self::check_argument_compat(
rust_abi, rust_abi,

View file

@ -217,7 +217,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
// Function arguments should be retagged, and we make this one raw. // Function arguments should be retagged, and we make this one raw.
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
source_info, source_info,
kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()), kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())),
}); });
} }
let patch = { let patch = {
@ -308,7 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span); 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(); let src = Place::from(Local::new(1+0)).deref();
match self_ty.sty { match self_ty.sty {
@ -415,8 +415,10 @@ impl CloneShimBuilder<'tcx> {
let rcvr = Place::from(Local::new(1+0)).deref(); let rcvr = Place::from(Local::new(1+0)).deref();
let ret_statement = self.make_statement( let ret_statement = self.make_statement(
StatementKind::Assign( StatementKind::Assign(
Place::RETURN_PLACE, box(
box Rvalue::Use(Operand::Copy(rcvr)) Place::return_place(),
Rvalue::Use(Operand::Copy(rcvr))
)
) )
); );
self.block(vec![ret_statement], TerminatorKind::Return, false); self.block(vec![ret_statement], TerminatorKind::Return, false);
@ -458,8 +460,10 @@ impl CloneShimBuilder<'tcx> {
// `let ref_loc: &ty = &src;` // `let ref_loc: &ty = &src;`
let statement = self.make_statement( let statement = self.make_statement(
StatementKind::Assign( StatementKind::Assign(
ref_loc.clone(), box(
box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src) ref_loc.clone(),
Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
)
) )
); );
@ -486,8 +490,10 @@ impl CloneShimBuilder<'tcx> {
let cond = self.make_place(Mutability::Mut, tcx.types.bool); let cond = self.make_place(Mutability::Mut, tcx.types.bool);
let compute_cond = self.make_statement( let compute_cond = self.make_statement(
StatementKind::Assign( StatementKind::Assign(
cond.clone(), box(
box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg)) cond.clone(),
Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
)
) )
); );
@ -521,14 +527,18 @@ impl CloneShimBuilder<'tcx> {
let inits = vec![ let inits = vec![
self.make_statement( self.make_statement(
StatementKind::Assign( StatementKind::Assign(
Place::from(beg), box(
box Rvalue::Use(Operand::Constant(self.make_usize(0))) Place::from(beg),
Rvalue::Use(Operand::Constant(self.make_usize(0)))
)
) )
), ),
self.make_statement( self.make_statement(
StatementKind::Assign( StatementKind::Assign(
end.clone(), box(
box Rvalue::Use(Operand::Constant(self.make_usize(len))) end.clone(),
Rvalue::Use(Operand::Constant(self.make_usize(len)))
)
) )
) )
]; ];
@ -559,11 +569,13 @@ impl CloneShimBuilder<'tcx> {
let statements = vec![ let statements = vec![
self.make_statement( self.make_statement(
StatementKind::Assign( StatementKind::Assign(
Place::from(beg), box(
box Rvalue::BinaryOp( Place::from(beg),
BinOp::Add, Rvalue::BinaryOp(
Operand::Copy(Place::from(beg)), BinOp::Add,
Operand::Constant(self.make_usize(1)) Operand::Copy(Place::from(beg)),
Operand::Constant(self.make_usize(1))
)
) )
) )
) )
@ -582,8 +594,10 @@ impl CloneShimBuilder<'tcx> {
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span)); let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
let init = self.make_statement( let init = self.make_statement(
StatementKind::Assign( StatementKind::Assign(
Place::from(beg), box(
box Rvalue::Use(Operand::Constant(self.make_usize(0))) Place::from(beg),
Rvalue::Use(Operand::Constant(self.make_usize(0)))
)
) )
); );
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true); self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
@ -609,11 +623,13 @@ impl CloneShimBuilder<'tcx> {
// `goto #6;` // `goto #6;`
let statement = self.make_statement( let statement = self.make_statement(
StatementKind::Assign( StatementKind::Assign(
Place::from(beg), box(
box Rvalue::BinaryOp( Place::from(beg),
BinOp::Add, Rvalue::BinaryOp(
Operand::Copy(Place::from(beg)), BinOp::Add,
Operand::Constant(self.make_usize(1)) Operand::Copy(Place::from(beg)),
Operand::Constant(self.make_usize(1))
)
) )
) )
); );
@ -727,8 +743,10 @@ fn build_call_shim<'tcx>(
statements.push(Statement { statements.push(Statement {
source_info, source_info,
kind: StatementKind::Assign( kind: StatementKind::Assign(
Place::from(ref_rcvr), box(
box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l) Place::from(ref_rcvr),
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
)
) )
}); });
Operand::Move(Place::from(ref_rcvr)) Operand::Move(Place::from(ref_rcvr))
@ -773,7 +791,7 @@ fn build_call_shim<'tcx>(
block(&mut blocks, statements, TerminatorKind::Call { block(&mut blocks, statements, TerminatorKind::Call {
func: callee, func: callee,
args, args,
destination: Some((Place::RETURN_PLACE, destination: Some((Place::return_place(),
BasicBlock::new(1))), BasicBlock::new(1))),
cleanup: if let Adjustment::RefMut = rcvr_adjustment { cleanup: if let Adjustment::RefMut = rcvr_adjustment {
Some(BasicBlock::new(3)) Some(BasicBlock::new(3))
@ -868,7 +886,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
debug!("build_ctor: variant_index={:?}", variant_index); debug!("build_ctor: variant_index={:?}", variant_index);
let statements = expand_aggregate( let statements = expand_aggregate(
Place::RETURN_PLACE, Place::return_place(),
adt_def adt_def
.variants[variant_index] .variants[variant_index]
.fields .fields

View file

@ -17,12 +17,11 @@ pub struct AddRetag;
fn is_stable( fn is_stable(
place: PlaceRef<'_, '_>, place: PlaceRef<'_, '_>,
) -> bool { ) -> bool {
if let Some(proj) = &place.projection { place.projection.iter().all(|elem| {
match proj.elem { match elem {
// Which place this evaluates to can change with any memory write, // Which place this evaluates to can change with any memory write,
// so cannot assume this to be stable. // so cannot assume this to be stable.
ProjectionElem::Deref => ProjectionElem::Deref => false,
false,
// Array indices are intersting, but MIR building generates a *fresh* // Array indices are intersting, but MIR building generates a *fresh*
// temporary for every array access, so the index cannot be changed as // temporary for every array access, so the index cannot be changed as
// a side-effect. // a side-effect.
@ -31,15 +30,9 @@ fn is_stable(
ProjectionElem::Field { .. } | ProjectionElem::Field { .. } |
ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. } |
ProjectionElem::Downcast { .. } => ProjectionElem::Downcast { .. } => true,
is_stable(PlaceRef {
base: place.base,
projection: &proj.base,
}),
} }
} else { })
true
}
} }
/// Determine whether this type may be a reference (or box), and thus needs retagging. /// Determine whether this type may be a reference (or box), and thus needs retagging.
@ -96,7 +89,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
basic_blocks[START_BLOCK].statements.splice(0..0, basic_blocks[START_BLOCK].statements.splice(0..0,
places.into_iter().map(|place| Statement { places.into_iter().map(|place| Statement {
source_info, source_info,
kind: StatementKind::Retag(RetagKind::FnEntry, place), kind: StatementKind::Retag(RetagKind::FnEntry, box(place)),
}) })
); );
} }
@ -132,7 +125,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
for (source_info, dest_place, dest_block) in returns { for (source_info, dest_place, dest_block) in returns {
basic_blocks[dest_block].statements.insert(0, Statement { basic_blocks[dest_block].statements.insert(0, Statement {
source_info, source_info,
kind: StatementKind::Retag(RetagKind::Default, dest_place), kind: StatementKind::Retag(RetagKind::Default, box(dest_place)),
}); });
} }
@ -144,11 +137,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
for i in (0..block_data.statements.len()).rev() { for i in (0..block_data.statements.len()).rev() {
let (retag_kind, place) = match block_data.statements[i].kind { let (retag_kind, place) = match block_data.statements[i].kind {
// If we are casting *from* a reference, we may have to retag-as-raw. // If we are casting *from* a reference, we may have to retag-as-raw.
StatementKind::Assign(ref place, box Rvalue::Cast( StatementKind::Assign(box(ref place, Rvalue::Cast(
CastKind::Misc, CastKind::Misc,
ref src, ref src,
dest_ty, dest_ty,
)) => { ))) => {
let src_ty = src.ty(&*local_decls, tcx); let src_ty = src.ty(&*local_decls, tcx);
if src_ty.is_region_ptr() { if src_ty.is_region_ptr() {
// The only `Misc` casts on references are those creating raw pointers. // The only `Misc` casts on references are those creating raw pointers.
@ -162,7 +155,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
// Assignments of reference or ptr type are the ones where we may have // Assignments of reference or ptr type are the ones where we may have
// to update tags. This includes `x = &[mut] ...` and hence // to update tags. This includes `x = &[mut] ...` and hence
// we also retag after taking a reference! // we also retag after taking a reference!
StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => { StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => {
let kind = match rvalue { let kind = match rvalue {
Rvalue::Ref(_, borrow_kind, _) Rvalue::Ref(_, borrow_kind, _)
if borrow_kind.allows_two_phase_borrow() if borrow_kind.allows_two_phase_borrow()
@ -180,7 +173,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
let source_info = block_data.statements[i].source_info; let source_info = block_data.statements[i].source_info;
block_data.statements.insert(i+1, Statement { block_data.statements.insert(i+1, Statement {
source_info, source_info,
kind: StatementKind::Retag(retag_kind, place), kind: StatementKind::Retag(retag_kind, box(place)),
}); });
} }
} }

View file

@ -200,127 +200,127 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
place: &Place<'tcx>, place: &Place<'tcx>,
context: PlaceContext, context: PlaceContext,
_location: Location) { _location: Location) {
place.iterate(|place_base, place_projections| { match place.base {
match place_base { PlaceBase::Local(..) => {
PlaceBase::Local(..) => { // Locals are safe.
// Locals are safe. }
} PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { bug!("unsafety checking should happen before promotion")
bug!("unsafety checking should happen before promotion") }
} PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { if self.tcx.is_mutable_static(def_id) {
if self.tcx.is_mutable_static(*def_id) { self.require_unsafe("use of mutable static",
self.require_unsafe("use of mutable static", "mutable statics can be mutated by multiple threads: aliasing \
"mutable statics can be mutated by multiple threads: aliasing \ violations or data races will cause undefined behavior",
violations or data races will cause undefined behavior", UnsafetyViolationKind::General);
UnsafetyViolationKind::General); } else if self.tcx.is_foreign_item(def_id) {
} else if self.tcx.is_foreign_item(*def_id) { let source_info = self.source_info;
let source_info = self.source_info; let lint_root =
let lint_root = self.source_scope_local_data[source_info.scope].lint_root;
self.source_scope_local_data[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation {
self.register_violations(&[UnsafetyViolation { source_info,
source_info, description: InternedString::intern("use of extern static"),
description: InternedString::intern("use of extern static"), details: InternedString::intern(
details: InternedString::intern( "extern statics are not controlled by the Rust type system: \
"extern statics are not controlled by the Rust type system: \ invalid data, aliasing violations or data races will cause \
invalid data, aliasing violations or data races will cause \ undefined behavior"),
undefined behavior"), kind: UnsafetyViolationKind::ExternStatic(lint_root)
kind: UnsafetyViolationKind::ExternStatic(lint_root) }], &[]);
}], &[]);
}
} }
} }
}
for proj in place_projections { for (i, elem) in place.projection.iter().enumerate() {
if context.is_borrow() { let proj_base = &place.projection[..i];
if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
let source_info = self.source_info; if context.is_borrow() {
let lint_root = if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
self.source_scope_local_data[source_info.scope].lint_root; let source_info = self.source_info;
self.register_violations(&[UnsafetyViolation { let lint_root =
source_info, self.source_scope_local_data[source_info.scope].lint_root;
description: InternedString::intern("borrow of packed field"), self.register_violations(&[UnsafetyViolation {
details: InternedString::intern( source_info,
"fields of packed structs might be misaligned: dereferencing a \ description: InternedString::intern("borrow of packed field"),
misaligned pointer or even just creating a misaligned reference \ details: InternedString::intern(
is undefined behavior"), "fields of packed structs might be misaligned: dereferencing a \
kind: UnsafetyViolationKind::BorrowPacked(lint_root) 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) let is_borrow_of_interior_mut = context.is_borrow() &&
.ty !Place::ty_from(&place.base, proj_base, self.body, self.tcx)
.is_freeze(self.tcx, self.param_env, self.source_info.span); .ty
// prevent .is_freeze(self.tcx, self.param_env, self.source_info.span);
// * `&mut x.field` // prevent
// * `x.field = y;` // * `&mut x.field`
// * `&x.field` if `field`'s type has interior mutability // * `x.field = y;`
// because either of these would allow modifying the layout constrained field and // * `&x.field` if `field`'s type has interior mutability
// insert values that violate the layout constraints. // because either of these would allow modifying the layout constrained field and
if context.is_mutating_use() || is_borrow_of_interior_mut { // insert values that violate the layout constraints.
self.check_mut_borrowing_layout_constrained_field( if context.is_mutating_use() || is_borrow_of_interior_mut {
place, context.is_mutating_use(), 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) { let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
if self.body.local_decls[*local].internal { match base_ty.sty {
// Internal locals are used in the `move_val_init` desugaring. ty::RawPtr(..) => {
// We want to check unsafety against the source info of the self.require_unsafe("dereference of raw pointer",
// desugaring, rather than the source info of the RHS. "raw pointers may be NULL, dangling or unaligned; they can violate \
self.source_info = self.body.local_decls[*local].source_info; 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; ty::Adt(adt, _) => {
match base_ty.sty { if adt.is_union() {
ty::RawPtr(..) => { if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
self.require_unsafe("dereference of raw pointer", context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
"raw pointers may be NULL, dangling or unaligned; they can violate \ context == PlaceContext::MutatingUse(
aliasing rules and cause data races: all of these are undefined \ MutatingUseContext::AsmOutput
behavior", UnsafetyViolationKind::General) )
} {
ty::Adt(adt, _) => { let elem_ty = match elem {
if adt.is_union() { ProjectionElem::Field(_, ty) => ty,
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) || _ => span_bug!(
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,
self.source_info.span, self.source_info.span,
) { "non-field projection {:?} from union?",
self.require_unsafe( place)
"assignment to non-`Copy` union field", };
"the previous content of the field will be dropped, which \ if !elem_ty.is_copy_modulo_regions(
causes undefined behavior if the field was not properly \ self.tcx,
initialized", UnsafetyViolationKind::General) self.param_env,
} else { self.source_info.span,
// write to non-move union, safe ) {
} 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 { } else {
self.require_unsafe("access to union field", // write to non-move union, safe
"the field may not be properly initialized: using \
uninitialized data will cause undefined behavior",
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)
} }
} }
_ => {}
} }
self.source_info = old_source_info; _ => {}
} }
}); self.source_info = old_source_info;
}
} }
} }
@ -407,12 +407,13 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
place: &Place<'tcx>, place: &Place<'tcx>,
is_mut_use: bool, is_mut_use: bool,
) { ) {
let mut projection = &place.projection; for (i, elem) in place.projection.iter().enumerate().rev() {
while let Some(proj) = projection { let proj_base = &place.projection[..i];
match proj.elem {
match elem {
ProjectionElem::Field(..) => { ProjectionElem::Field(..) => {
let ty = 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; .ty;
match ty.sty { match ty.sty {
ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
@ -447,7 +448,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
} }
_ => {} _ => {}
} }
projection = &proj.base;
} }
} }
} }

View file

@ -39,7 +39,7 @@ impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements {
location: Location) { location: Location) {
match statement.kind { match statement.kind {
StatementKind::AscribeUserType(..) StatementKind::AscribeUserType(..)
| StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _)) | StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
| StatementKind::FakeRead(..) => statement.make_nop(), | StatementKind::FakeRead(..) => statement.make_nop(),
_ => (), _ => (),
} }

View file

@ -282,53 +282,53 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> { fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
trace!("eval_place(place={:?})", place); trace!("eval_place(place={:?})", place);
place.iterate(|place_base, place_projection| { let mut eval = match place.base {
let mut eval = match place_base { PlaceBase::Local(loc) => self.get_const(loc).clone()?,
PlaceBase::Local(loc) => self.get_const(*loc).clone()?, PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => { let generics = self.tcx.generics_of(self.source.def_id());
let generics = self.tcx.generics_of(self.source.def_id()); if generics.requires_monomorphization(self.tcx) {
if generics.requires_monomorphization(self.tcx) { // FIXME: can't handle code with generics
// FIXME: can't handle code with generics return None;
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 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,
} }
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,
};
Some(eval) 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)
})?;
},
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)
} }
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> { fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
@ -665,7 +665,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
location: Location, location: Location,
) { ) {
trace!("visit_statement: {:?}", statement); trace!("visit_statement: {:?}", statement);
if let StatementKind::Assign(ref place, ref mut rval) = statement.kind { if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind {
let place_ty: Ty<'tcx> = place let place_ty: Ty<'tcx> = place
.ty(&self.local_decls, self.tcx) .ty(&self.local_decls, self.tcx)
.ty; .ty;
@ -673,7 +673,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
if let Place { if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = *place { } = *place {
trace!("checking whether {:?} can be stored to {:?}", value, local); trace!("checking whether {:?} can be stored to {:?}", value, local);
if self.can_const_prop[local] { if self.can_const_prop[local] {

View file

@ -94,11 +94,13 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
// That use of the source must be an assignment. // That use of the source must be an assignment.
match statement.kind { match statement.kind {
StatementKind::Assign( StatementKind::Assign(
Place { box(
base: PlaceBase::Local(local), Place {
projection: None, base: PlaceBase::Local(local),
}, projection: box [],
box Rvalue::Use(ref operand) },
Rvalue::Use(ref operand)
)
) if local == dest_local => { ) if local == dest_local => {
let maybe_action = match *operand { let maybe_action = match *operand {
Operand::Copy(ref src_place) | Operand::Copy(ref src_place) |
@ -148,24 +150,28 @@ fn eliminate_self_assignments(
if let Some(stmt) = body[location.block].statements.get(location.statement_index) { if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
match stmt.kind { match stmt.kind {
StatementKind::Assign( StatementKind::Assign(
Place { box(
base: PlaceBase::Local(local), Place {
projection: None, base: PlaceBase::Local(local),
}, projection: box [],
box Rvalue::Use(Operand::Copy(Place { },
base: PlaceBase::Local(src_local), Rvalue::Use(Operand::Copy(Place {
projection: None, base: PlaceBase::Local(src_local),
})), projection: box [],
})),
)
) | ) |
StatementKind::Assign( StatementKind::Assign(
Place { box(
base: PlaceBase::Local(local), Place {
projection: None, base: PlaceBase::Local(local),
}, projection: box [],
box Rvalue::Use(Operand::Move(Place { },
base: PlaceBase::Local(src_local), Rvalue::Use(Operand::Move(Place {
projection: None, base: PlaceBase::Local(src_local),
})), projection: box [],
})),
)
) if local == dest_local && dest_local == src_local => {} ) if local == dest_local && dest_local == src_local => {}
_ => { _ => {
continue; continue;
@ -194,7 +200,7 @@ impl<'tcx> Action<'tcx> {
// The source must be a local. // The source must be a local.
let src_local = if let Place { let src_local = if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = *src_place { } = *src_place {
local local
} else { } else {
@ -351,11 +357,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
match *operand { match *operand {
Operand::Copy(Place { Operand::Copy(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}) | }) |
Operand::Move(Place { Operand::Move(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}) if local == self.dest_local => {} }) if local == self.dest_local => {}
_ => return, _ => return,
} }

View file

@ -12,8 +12,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
for bb in basic_blocks { for bb in basic_blocks {
bb.expand_statements(|stmt| { bb.expand_statements(|stmt| {
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
if let StatementKind::Assign(_, ref rhs) = stmt.kind { if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind {
if let Rvalue::Aggregate(ref kind, _) = **rhs { if let Rvalue::Aggregate(ref kind, _) = *rhs {
// FIXME(#48193) Deaggregate arrays when it's cheaper to do so. // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
if let AggregateKind::Array(_) = **kind { if let AggregateKind::Array(_) = **kind {
return None; return None;
@ -28,7 +28,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
let stmt = stmt.replace_nop(); let stmt = stmt.replace_nop();
let source_info = stmt.source_info; let source_info = stmt.source_info;
let (lhs, kind, operands) = match stmt.kind { let (lhs, kind, operands) = match stmt.kind {
StatementKind::Assign(lhs, box rvalue) => { StatementKind::Assign(box(lhs, rvalue)) => {
match rvalue { match rvalue {
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands), Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
_ => bug!() _ => bug!()

View file

@ -236,47 +236,34 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
} }
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> { fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
match p { ProjectionElem::Field(idx, _) => *idx == field,
&Projection { _ => false,
elem: ProjectionElem::Field(idx, _), ..
} => idx == field,
_ => false
}
}) })
} }
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> { 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| { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
match p { ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
&Projection { *offset == index
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
} }
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
size - offset == index
}
_ => false,
}) })
} }
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> { fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
match p { *e == ProjectionElem::Deref
&Projection { elem: ProjectionElem::Deref, .. } => true,
_ => false
}
}) })
} }
fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> { fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
match p { ProjectionElem::Downcast(_, idx) => *idx == variant,
&Projection { _ => false
elem: ProjectionElem::Downcast(_, idx), ..
} => idx == variant,
_ => false
}
}) })
} }
@ -465,7 +452,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
let assign = Statement { let assign = Statement {
kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())), kind: StatementKind::Assign(box(location.clone(), Rvalue::Use(value.clone()))),
source_info: terminator.source_info source_info: terminator.source_info
}; };

View file

@ -107,10 +107,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
if place.base == PlaceBase::Local(self_arg()) { if place.base == PlaceBase::Local(self_arg()) {
replace_base(place, Place { replace_base(place, Place {
base: PlaceBase::Local(self_arg()), base: PlaceBase::Local(self_arg()),
projection: Some(Box::new(Projection { projection: Box::new([ProjectionElem::Deref]),
base: None,
elem: ProjectionElem::Deref,
})),
}); });
} else { } else {
self.super_place(place, context, location); self.super_place(place, context, location);
@ -137,10 +134,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
if place.base == PlaceBase::Local(self_arg()) { if place.base == PlaceBase::Local(self_arg()) {
replace_base(place, Place { replace_base(place, Place {
base: PlaceBase::Local(self_arg()), base: PlaceBase::Local(self_arg()),
projection: Some(Box::new(Projection { projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
base: None,
elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
})),
}); });
} else { } else {
self.super_place(place, context, location); self.super_place(place, context, location);
@ -149,13 +143,12 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
} }
fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) { 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; 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 self_arg() -> Local {
@ -210,13 +203,12 @@ impl TransformVisitor<'tcx> {
fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
let self_place = Place::from(self_arg()); let self_place = Place::from(self_arg());
let base = self_place.downcast_unnamed(variant_index); let base = self_place.downcast_unnamed(variant_index);
let field = Projection { let mut projection = base.projection.to_vec();
base: base.projection, projection.push(ProjectionElem::Field(Field::new(idx), ty));
elem: ProjectionElem::Field(Field::new(idx), ty),
};
Place { Place {
base: base.base, base: base.base,
projection: Some(Box::new(field)), projection: projection.into_boxed_slice(),
} }
} }
@ -225,7 +217,10 @@ impl TransformVisitor<'tcx> {
let self_place = Place::from(self_arg()); let self_place = Place::from(self_arg());
Statement { Statement {
source_info, source_info,
kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc }, kind: StatementKind::SetDiscriminant {
place: box self_place,
variant_index: state_disc,
},
} }
} }
@ -238,7 +233,7 @@ impl TransformVisitor<'tcx> {
let self_place = Place::from(self_arg()); let self_place = Place::from(self_arg());
let assign = Statement { let assign = Statement {
source_info: source_info(body), source_info: source_info(body),
kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)), kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))),
}; };
(assign, temp) (assign, temp)
} }
@ -296,8 +291,12 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
// We must assign the value first in case it gets declared dead below // We must assign the value first in case it gets declared dead below
data.statements.push(Statement { data.statements.push(Statement {
source_info, source_info,
kind: StatementKind::Assign(Place::RETURN_PLACE, kind: StatementKind::Assign(
box self.make_state(state_idx, v)), box(
Place::return_place(),
self.make_state(state_idx, v)
)
),
}); });
let state = if let Some(resume) = resume { // Yield let state = if let Some(resume) = resume { // Yield
let state = 3 + self.suspension_points.len(); let state = 3 + self.suspension_points.len();
@ -848,7 +847,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
kind: TerminatorKind::Drop { kind: TerminatorKind::Drop {
location: Place { location: Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}, },
target, target,
unwind unwind
@ -937,7 +936,7 @@ fn create_generator_drop_shim<'tcx>(
// Alias tracking must know we changed the type // Alias tracking must know we changed the type
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement { body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
source_info, source_info,
kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())), kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())),
}) })
} }

View file

@ -425,22 +425,20 @@ impl Inliner<'tcx> {
// writes to `i`. To prevent this we need to create a temporary // writes to `i`. To prevent this we need to create a temporary
// borrow of the place and pass the destination as `*temp` instead. // borrow of the place and pass the destination as `*temp` instead.
fn dest_needs_borrow(place: &Place<'_>) -> bool { fn dest_needs_borrow(place: &Place<'_>) -> bool {
place.iterate(|place_base, place_projection| { for elem in place.projection.iter() {
for proj in place_projection { match elem {
match proj.elem { ProjectionElem::Deref |
ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
ProjectionElem::Index(_) => return true, _ => {}
_ => {}
}
} }
}
match place_base { match place.base {
// Static variables need a borrow because the callee // Static variables need a borrow because the callee
// might modify the same static. // might modify the same static.
PlaceBase::Static(_) => true, PlaceBase::Static(_) => true,
_ => false _ => false
} }
})
} }
let dest = if dest_needs_borrow(&destination.0) { let dest = if dest_needs_borrow(&destination.0) {
@ -459,7 +457,7 @@ impl Inliner<'tcx> {
let stmt = Statement { let stmt = Statement {
source_info: callsite.location, source_info: callsite.location,
kind: StatementKind::Assign(tmp.clone(), box dest) kind: StatementKind::Assign(box(tmp.clone(), dest))
}; };
caller_body[callsite.bb] caller_body[callsite.bb]
.statements.push(stmt); .statements.push(stmt);
@ -591,7 +589,7 @@ impl Inliner<'tcx> {
if let Operand::Move(Place { if let Operand::Move(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}) = arg { }) = arg {
if caller_body.local_kind(local) == LocalKind::Temp { if caller_body.local_kind(local) == LocalKind::Temp {
// Reuse the operand if it's a temporary already // Reuse the operand if it's a temporary already
@ -610,7 +608,7 @@ impl Inliner<'tcx> {
let stmt = Statement { let stmt = Statement {
source_info: callsite.location, source_info: callsite.location,
kind: StatementKind::Assign(Place::from(arg_tmp), box arg), kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)),
}; };
caller_body[callsite.bb].statements.push(stmt); caller_body[callsite.bb].statements.push(stmt);
arg_tmp arg_tmp
@ -660,7 +658,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
match self.destination { match self.destination {
Place { Place {
base: PlaceBase::Local(l), base: PlaceBase::Local(l),
projection: None, projection: box [],
} => { } => {
*local = l; *local = l;
return; return;
@ -684,7 +682,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
match place { match place {
Place { Place {
base: PlaceBase::Local(RETURN_PLACE), base: PlaceBase::Local(RETURN_PLACE),
projection: None, projection: box [],
} => { } => {
// Return pointer; update the place itself // Return pointer; update the place itself
*place = self.destination.clone(); *place = self.destination.clone();

View file

@ -43,12 +43,21 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
let new_place = match *rvalue { let new_place = match *rvalue {
Rvalue::Ref(_, _, Place { Rvalue::Ref(_, _, Place {
ref mut base, ref mut base,
projection: Some(ref mut projection), projection: ref mut projection @ box [.., _],
}) => Place { }) => {
// Replace with dummy if let box [proj_l @ .., proj_r] = projection {
base: mem::replace(base, PlaceBase::Local(Local::new(0))), let place = Place {
projection: projection.base.take(), // Replace with dummy
}, base: mem::replace(base, PlaceBase::Local(Local::new(0))),
projection: proj_l.to_vec().into_boxed_slice(),
};
*projection = vec![proj_r.clone()].into_boxed_slice();
place
} else {
unreachable!();
}
}
_ => bug!("Detected `&*` but didn't find `&*`!"), _ => bug!("Detected `&*` but didn't find `&*`!"),
}; };
*rvalue = Rvalue::Use(Operand::Copy(new_place)) *rvalue = Rvalue::Use(Operand::Copy(new_place))
@ -83,13 +92,11 @@ impl OptimizationFinder<'b, 'tcx> {
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
if let Rvalue::Ref(_, _, Place { if let Rvalue::Ref(_, _, Place {
ref base, base,
projection: Some(ref projection), projection: box [proj_base @ .., ProjectionElem::Deref],
}) = *rvalue { }) = rvalue {
if let ProjectionElem::Deref = projection.elem { if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() { self.optimizations.and_stars.insert(location);
self.optimizations.and_stars.insert(location);
}
} }
} }

View file

@ -187,7 +187,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
span, span,
scope: OUTERMOST_SOURCE_SCOPE scope: OUTERMOST_SOURCE_SCOPE
}, },
kind: StatementKind::Assign(Place::from(dest), box rvalue) kind: StatementKind::Assign(box(Place::from(dest), rvalue))
}); });
} }
@ -222,10 +222,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
// First, take the Rvalue or Call out of the source MIR, // First, take the Rvalue or Call out of the source MIR,
// or duplicate it, depending on keep_original. // or duplicate it, depending on keep_original.
if loc.statement_index < no_stmts { if loc.statement_index < no_stmts {
let (rvalue, source_info) = { let (mut rvalue, source_info) = {
let statement = &mut self.source[loc.block].statements[loc.statement_index]; let statement = &mut self.source[loc.block].statements[loc.statement_index];
let rhs = match statement.kind { let rhs = match statement.kind {
StatementKind::Assign(_, ref mut rhs) => rhs, StatementKind::Assign(box(_, ref mut rhs)) => rhs,
_ => { _ => {
span_bug!(statement.source_info.span, "{:?} is not an assignment", span_bug!(statement.source_info.span, "{:?} is not an assignment",
statement); statement);
@ -235,12 +235,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
(if self.keep_original { (if self.keep_original {
rhs.clone() rhs.clone()
} else { } else {
let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]); let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
mem::replace(rhs, unit) mem::replace(rhs, unit)
}, statement.source_info) }, statement.source_info)
}; };
let mut rvalue = *rvalue;
self.visit_rvalue(&mut rvalue, loc); self.visit_rvalue(&mut rvalue, loc);
self.assign(new_temp, rvalue, source_info.span); self.assign(new_temp, rvalue, source_info.span);
} else { } else {
@ -318,7 +317,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
ty, ty,
def_id, def_id,
}), }),
projection: None, projection: box [],
} }
}; };
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
@ -326,7 +325,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
Candidate::Ref(loc) => { Candidate::Ref(loc) => {
let ref mut statement = blocks[loc.block].statements[loc.statement_index]; let ref mut statement = blocks[loc.block].statements[loc.statement_index];
match statement.kind { match statement.kind {
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => { StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
// Use the underlying local for this (necessarily interior) borrow. // Use the underlying local for this (necessarily interior) borrow.
let ty = place.base.ty(local_decls).ty; let ty = place.base.ty(local_decls).ty;
let span = statement.source_info.span; let span = statement.source_info.span;
@ -334,9 +333,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
Operand::Move(Place { Operand::Move(Place {
base: mem::replace( base: mem::replace(
&mut place.base, &mut place.base,
promoted_place(ty, span).base promoted_place(ty, span).base,
), ),
projection: None, projection: box [],
}) })
} }
_ => bug!() _ => bug!()
@ -345,7 +344,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
Candidate::Repeat(loc) => { Candidate::Repeat(loc) => {
let ref mut statement = blocks[loc.block].statements[loc.statement_index]; let ref mut statement = blocks[loc.block].statements[loc.statement_index];
match statement.kind { match statement.kind {
StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => { StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => {
let ty = operand.ty(local_decls, self.tcx); let ty = operand.ty(local_decls, self.tcx);
let span = statement.source_info.span; let span = statement.source_info.span;
mem::replace( mem::replace(
@ -420,10 +419,10 @@ pub fn promote_candidates<'tcx>(
Candidate::Repeat(Location { block, statement_index }) | Candidate::Repeat(Location { block, statement_index }) |
Candidate::Ref(Location { block, statement_index }) => { Candidate::Ref(Location { block, statement_index }) => {
match body[block].statements[statement_index].kind { match body[block].statements[statement_index].kind {
StatementKind::Assign(Place { StatementKind::Assign(box(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}, _) => { }, _)) => {
if temps[local] == TempState::PromotedOut { if temps[local] == TempState::PromotedOut {
// Already promoted. // Already promoted.
continue; continue;
@ -473,10 +472,10 @@ pub fn promote_candidates<'tcx>(
for block in body.basic_blocks_mut() { for block in body.basic_blocks_mut() {
block.statements.retain(|statement| { block.statements.retain(|statement| {
match statement.kind { match statement.kind {
StatementKind::Assign(Place { StatementKind::Assign(box(Place {
base: PlaceBase::Local(index), base: PlaceBase::Local(index),
projection: None, projection: box [],
}, _) | }, _)) |
StatementKind::StorageLive(index) | StatementKind::StorageLive(index) |
StatementKind::StorageDead(index) => { StatementKind::StorageDead(index) => {
!promoted(index) !promoted(index)
@ -488,7 +487,7 @@ pub fn promote_candidates<'tcx>(
match terminator.kind { match terminator.kind {
TerminatorKind::Drop { location: Place { TerminatorKind::Drop { location: Place {
base: PlaceBase::Local(index), base: PlaceBase::Local(index),
projection: None, projection: box [],
}, target, .. } => { }, target, .. } => {
if promoted(index) { if promoted(index) {
terminator.kind = TerminatorKind::Goto { terminator.kind = TerminatorKind::Goto {

View file

@ -187,26 +187,28 @@ trait Qualif {
cx: &ConstCx<'_, 'tcx>, cx: &ConstCx<'_, 'tcx>,
place: PlaceRef<'_, 'tcx>, place: PlaceRef<'_, 'tcx>,
) -> bool { ) -> bool {
let proj = place.projection.as_ref().unwrap(); if let [proj_base @ .., elem] = place.projection {
let base_qualif = Self::in_place(cx, PlaceRef {
base: place.base,
projection: proj_base,
});
let qualif = base_qualif && Self::mask_for_ty(
cx,
Place::ty_from(place.base, proj_base, cx.body, cx.tcx)
.projection_ty(cx.tcx, elem)
.ty,
);
match elem {
ProjectionElem::Deref |
ProjectionElem::Subslice { .. } |
ProjectionElem::Field(..) |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Downcast(..) => qualif,
let base_qualif = Self::in_place(cx, PlaceRef { ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local),
base: place.base, }
projection: &proj.base, } else {
}); bug!("This should be called if projection is not empty");
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)
.ty,
);
match proj.elem {
ProjectionElem::Deref |
ProjectionElem::Subslice { .. } |
ProjectionElem::Field(..) |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Downcast(..) => qualif,
ProjectionElem::Index(local) => qualif || Self::in_local(cx, local),
} }
} }
@ -221,24 +223,24 @@ trait Qualif {
match place { match place {
PlaceRef { PlaceRef {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: [],
} => Self::in_local(cx, *local), } => Self::in_local(cx, *local),
PlaceRef { PlaceRef {
base: PlaceBase::Static(box Static { base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
.. ..
}), }),
projection: None, projection: [],
} => bug!("qualifying already promoted MIR"), } => bug!("qualifying already promoted MIR"),
PlaceRef { PlaceRef {
base: PlaceBase::Static(static_), base: PlaceBase::Static(static_),
projection: None, projection: [],
} => { } => {
Self::in_static(cx, static_) Self::in_static(cx, static_)
}, },
PlaceRef { PlaceRef {
base: _, base: _,
projection: Some(_), projection: [.., _],
} => Self::in_projection(cx, place), } => Self::in_projection(cx, place),
} }
} }
@ -289,13 +291,13 @@ trait Qualif {
Rvalue::Ref(_, _, ref place) => { Rvalue::Ref(_, _, ref place) => {
// Special-case reborrows to be more like a copy of the reference. // Special-case reborrows to be more like a copy of the reference.
if let Some(ref proj) = place.projection { if let box [proj_base @ .., elem] = &place.projection {
if let ProjectionElem::Deref = proj.elem { if ProjectionElem::Deref == *elem {
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 ty::Ref(..) = base_ty.sty { if let ty::Ref(..) = base_ty.sty {
return Self::in_place(cx, PlaceRef { return Self::in_place(cx, PlaceRef {
base: &place.base, base: &place.base,
projection: &proj.base, projection: proj_base,
}); });
} }
} }
@ -453,30 +455,32 @@ impl Qualif for IsNotPromotable {
cx: &ConstCx<'_, 'tcx>, cx: &ConstCx<'_, 'tcx>,
place: PlaceRef<'_, 'tcx>, place: PlaceRef<'_, 'tcx>,
) -> bool { ) -> bool {
let proj = place.projection.as_ref().unwrap(); if let [proj_base @ .., elem] = place.projection {
match elem {
ProjectionElem::Deref |
ProjectionElem::Downcast(..) => return true,
match proj.elem { ProjectionElem::ConstantIndex {..} |
ProjectionElem::Deref | ProjectionElem::Subslice {..} |
ProjectionElem::Downcast(..) => return true, ProjectionElem::Index(_) => {}
ProjectionElem::ConstantIndex {..} | ProjectionElem::Field(..) => {
ProjectionElem::Subslice {..} | if cx.mode == Mode::NonConstFn {
ProjectionElem::Index(_) => {} let base_ty = Place::ty_from(place.base, proj_base, cx.body, cx.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
ProjectionElem::Field(..) => { // No promotion of union field accesses.
if cx.mode == Mode::NonConstFn { if def.is_union() {
let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty; return true;
if let Some(def) = base_ty.ty_adt_def() { }
// No promotion of union field accesses.
if def.is_union() {
return true;
} }
} }
} }
} }
}
Self::in_projection_structurally(cx, place) Self::in_projection_structurally(cx, place)
} else {
bug!("This should be called if projection is not empty");
}
} }
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool { fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
@ -806,23 +810,18 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
// We might have a candidate for promotion. // We might have a candidate for promotion.
let candidate = Candidate::Ref(location); let candidate = Candidate::Ref(location);
// Start by traversing to the "base", with non-deref projections removed. // Start by traversing to the "base", with non-deref projections removed.
let mut place_projection = &place.projection; let deref_proj =
while let Some(proj) = place_projection { place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref);
if proj.elem == ProjectionElem::Deref {
break;
}
place_projection = &proj.base;
}
debug!( debug!(
"qualify_consts: promotion candidate: place={:?} {:?}", "qualify_consts: promotion candidate: place={:?} {:?}",
place.base, place_projection place.base, deref_proj
); );
// We can only promote interior borrows of promotable temps (non-temps // We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway). // don't get promoted anyway).
// (If we bailed out of the loop due to a `Deref` above, we will definitely // (If we bailed out of the loop due to a `Deref` above, we will definitely
// not enter the conditional here.) // 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 { if self.body.local_kind(*local) == LocalKind::Temp {
debug!("qualify_consts: promotion candidate: local={:?}", local); debug!("qualify_consts: promotion candidate: local={:?}", local);
// The borrowed place doesn't have `HasMutInterior` // The borrowed place doesn't have `HasMutInterior`
@ -858,27 +857,27 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
_ => {}, _ => {},
} }
let mut dest_projection = &dest.projection; let mut dest_projection = &dest.projection[..];
let index = loop { let index = loop {
match (&dest.base, dest_projection) { match (&dest.base, dest_projection) {
// We treat all locals equal in constants // We treat all locals equal in constants
(&PlaceBase::Local(index), None) => break index, (&PlaceBase::Local(index), []) => break index,
// projections are transparent for assignments // projections are transparent for assignments
// we qualify the entire destination at once, even if just a field would have // we qualify the entire destination at once, even if just a field would have
// stricter qualification // stricter qualification
(base, Some(proj)) => { (base, [proj_base @ .., _]) => {
// Catch more errors in the destination. `visit_place` also checks various // Catch more errors in the destination. `visit_place` also checks various
// projection rules like union field access and raw pointer deref // projection rules like union field access and raw pointer deref
let context = PlaceContext::MutatingUse(MutatingUseContext::Store); let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
self.visit_place_base(base, context, location); self.visit_place_base(base, context, location);
self.visit_projection(base, proj, context, location); self.visit_projection(base, dest_projection, context, location);
dest_projection = &proj.base; dest_projection = proj_base;
}, },
(&PlaceBase::Static(box Static { (&PlaceBase::Static(box Static {
kind: StaticKind::Promoted(..), kind: StaticKind::Promoted(..),
.. ..
}), None) => bug!("promoteds don't exist yet during promotion"), }), []) => bug!("promoteds don't exist yet during promotion"),
(&PlaceBase::Static(box Static{ kind: _, .. }), None) => { (&PlaceBase::Static(box Static{ kind: _, .. }), []) => {
// Catch more errors in the destination. `visit_place` also checks that we // 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 // do not try to access statics from constants or try to mutate statics
let context = PlaceContext::MutatingUse(MutatingUseContext::Store); let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
@ -983,23 +982,25 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
for candidate in &self.promotion_candidates { for candidate in &self.promotion_candidates {
match *candidate { match *candidate {
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => { Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign(_, box Rvalue::Repeat( if let StatementKind::Assign(box(_, Rvalue::Repeat(
Operand::Move(Place { Operand::Move(Place {
base: PlaceBase::Local(index), base: PlaceBase::Local(index),
projection: None, projection: box [],
}), }),
_ _
)) = self.body[bb].statements[stmt_idx].kind { ))) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index); promoted_temps.insert(index);
} }
} }
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => { Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign( if let StatementKind::Assign(
_, box(
box Rvalue::Ref(_, _, Place { _,
base: PlaceBase::Local(index), Rvalue::Ref(_, _, Place {
projection: None, base: PlaceBase::Local(index),
}) projection: box [],
})
)
) = self.body[bb].statements[stmt_idx].kind { ) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index); promoted_temps.insert(index);
} }
@ -1084,7 +1085,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
fn visit_projection( fn visit_projection(
&mut self, &mut self,
place_base: &PlaceBase<'tcx>, place_base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>, proj: &[PlaceElem<'tcx>],
context: PlaceContext, context: PlaceContext,
location: Location, location: Location,
) { ) {
@ -1093,62 +1094,65 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
proj, context, location, proj, context, location,
); );
self.super_projection(place_base, proj, context, location); self.super_projection(place_base, proj, context, location);
match proj.elem {
ProjectionElem::Deref => { if let [proj_base @ .., elem] = proj {
if context.is_mutating_use() { match elem {
// `not_const` errors out in const contexts ProjectionElem::Deref => {
self.not_const() if context.is_mutating_use() {
} // `not_const` errors out in const contexts
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; self.not_const()
match self.mode { }
Mode::NonConstFn => {}, let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
_ => { match self.mode {
if let ty::RawPtr(_) = base_ty.sty { Mode::NonConstFn => {},
if !self.tcx.features().const_raw_ptr_deref { _ => {
emit_feature_err( if let ty::RawPtr(_) = base_ty.sty {
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref, if !self.tcx.features().const_raw_ptr_deref {
self.span, GateIssue::Language, emit_feature_err(
&format!( &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
"dereferencing raw pointers in {}s is unstable", self.span, GateIssue::Language,
self.mode, &format!(
), "dereferencing raw pointers in {}s is unstable",
); self.mode,
),
);
}
} }
} }
} }
} }
}
ProjectionElem::ConstantIndex {..} | ProjectionElem::ConstantIndex {..} |
ProjectionElem::Subslice {..} | ProjectionElem::Subslice {..} |
ProjectionElem::Field(..) | ProjectionElem::Field(..) |
ProjectionElem::Index(_) => { ProjectionElem::Index(_) => {
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty; let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() { if let Some(def) = base_ty.ty_adt_def() {
if def.is_union() { if def.is_union() {
match self.mode { match self.mode {
Mode::ConstFn => { Mode::ConstFn => {
if !self.tcx.features().const_fn_union { if !self.tcx.features().const_fn_union {
emit_feature_err( emit_feature_err(
&self.tcx.sess.parse_sess, sym::const_fn_union, &self.tcx.sess.parse_sess, sym::const_fn_union,
self.span, GateIssue::Language, self.span, GateIssue::Language,
"unions in const fn are unstable", "unions in const fn are unstable",
); );
} }
}, },
| Mode::NonConstFn | Mode::NonConstFn
| Mode::Static | Mode::Static
| Mode::StaticMut | Mode::StaticMut
| Mode::Const | Mode::Const
=> {}, => {},
}
} }
} }
} }
}
ProjectionElem::Downcast(..) => { ProjectionElem::Downcast(..) => {
self.not_const() self.not_const()
}
} }
} }
} }
@ -1162,7 +1166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
// Mark the consumed locals to indicate later drops are noops. // Mark the consumed locals to indicate later drops are noops.
if let Place { if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = *place { } = *place {
self.cx.per_local[NeedsDrop].remove(local); self.cx.per_local[NeedsDrop].remove(local);
} }
@ -1179,11 +1183,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
if let Rvalue::Ref(_, kind, ref place) = *rvalue { if let Rvalue::Ref(_, kind, ref place) = *rvalue {
// Special-case reborrows. // Special-case reborrows.
let mut reborrow_place = None; let mut reborrow_place = None;
if let Some(ref proj) = place.projection { if let box [proj_base @ .., elem] = &place.projection {
if let ProjectionElem::Deref = proj.elem { if *elem == ProjectionElem::Deref {
let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty; let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.sty { if let ty::Ref(..) = base_ty.sty {
reborrow_place = Some(&proj.base); reborrow_place = Some(proj_base);
} }
} }
} }
@ -1204,9 +1208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
), ),
}; };
self.visit_place_base(&place.base, ctx, location); 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 { } else {
self.super_rvalue(rvalue, location); self.super_rvalue(rvalue, location);
} }
@ -1477,7 +1479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
// conservatively, that drop elaboration will do. // conservatively, that drop elaboration will do.
let needs_drop = if let Place { let needs_drop = if let Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
} = *place { } = *place {
if NeedsDrop::in_local(self, local) { if NeedsDrop::in_local(self, local) {
Some(self.body.local_decls[local].source_info.span) Some(self.body.local_decls[local].source_info.span)
@ -1727,7 +1729,7 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
TerminatorKind::Drop { TerminatorKind::Drop {
location: Place { location: Place {
base: PlaceBase::Local(index), base: PlaceBase::Local(index),
projection: None, projection: box [],
}, },
target, target,
.. ..

View file

@ -206,7 +206,7 @@ fn check_statement(
) -> McfResult { ) -> McfResult {
let span = statement.source_info.span; let span = statement.source_info.span;
match &statement.kind { match &statement.kind {
StatementKind::Assign(place, rval) => { StatementKind::Assign(box(place, rval)) => {
check_place(place, span)?; check_place(place, span)?;
check_rvalue(tcx, body, rval, span) check_rvalue(tcx, body, rval, span)
} }
@ -249,28 +249,26 @@ fn check_place(
place: &Place<'tcx>, place: &Place<'tcx>,
span: Span, span: Span,
) -> McfResult { ) -> McfResult {
place.iterate(|place_base, place_projection| { for elem in place.projection.iter() {
for proj in place_projection { match elem {
match proj.elem { ProjectionElem::Downcast(..) => {
ProjectionElem::Downcast(..) => { return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
}
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Deref
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
} }
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Deref
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
} }
}
match place_base { match place.base {
PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
Err((span, "cannot access `static` items in const fn".into())) Err((span, "cannot access `static` items in const fn".into()))
}
PlaceBase::Local(_)
| PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
} }
}) PlaceBase::Local(_)
| PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
}
} }
fn check_terminator( fn check_terminator(

View file

@ -41,10 +41,10 @@ impl RemoveNoopLandingPads {
// These are all nops in a landing pad // These are all nops in a landing pad
} }
StatementKind::Assign(Place { StatementKind::Assign(box(Place {
base: PlaceBase::Local(_), base: PlaceBase::Local(_),
projection: None, projection: box [],
}, box Rvalue::Use(_)) => { }, Rvalue::Use(_))) => {
// Writing to a local (e.g., a drop flag) does not // Writing to a local (e.g., a drop flag) does not
// turn a landing pad to a non-nop // turn a landing pad to a non-nop
} }

View file

@ -120,11 +120,11 @@ fn each_block<'tcx, O>(
let peek_arg_place = match args[0] { let peek_arg_place = match args[0] {
mir::Operand::Copy(ref place @ mir::Place { mir::Operand::Copy(ref place @ mir::Place {
base: mir::PlaceBase::Local(_), base: mir::PlaceBase::Local(_),
projection: None, projection: box [],
}) | }) |
mir::Operand::Move(ref place @ mir::Place { mir::Operand::Move(ref place @ mir::Place {
base: mir::PlaceBase::Local(_), base: mir::PlaceBase::Local(_),
projection: None, projection: box [],
}) => Some(place), }) => Some(place),
_ => None, _ => None,
}; };
@ -150,7 +150,7 @@ fn each_block<'tcx, O>(
for (j, stmt) in statements.iter().enumerate() { for (j, stmt) in statements.iter().enumerate() {
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
let (place, rvalue) = match stmt.kind { let (place, rvalue) = match stmt.kind {
mir::StatementKind::Assign(ref place, ref rvalue) => { mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
(place, rvalue) (place, rvalue)
} }
mir::StatementKind::FakeRead(..) | mir::StatementKind::FakeRead(..) |
@ -166,7 +166,7 @@ fn each_block<'tcx, O>(
}; };
if place == peek_arg_place { if place == peek_arg_place {
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue { if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
// Okay, our search is over. // Okay, our search is over.
match move_data.rev_lookup.find(peeking_at_place.as_ref()) { match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
LookupResult::Exact(peek_mpi) => { LookupResult::Exact(peek_mpi) => {

View file

@ -61,14 +61,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
rvalue: &Rvalue<'tcx>, rvalue: &Rvalue<'tcx>,
location: Location) { location: Location) {
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue { if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
if let Some(ref proj) = src_place.projection { if let box [proj_base @ .., elem] = &src_place.projection {
if let ProjectionElem::ConstantIndex{offset: _, if let ProjectionElem::ConstantIndex{offset: _,
min_length: _, min_length: _,
from_end: false} = proj.elem { from_end: false} = elem {
// no need to transformation // no need to transformation
} else { } else {
let place_ty = 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 ty::Array(item_ty, const_size) = place_ty.sty {
if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) { if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
assert!(size <= u32::max_value() as u64, assert!(size <= u32::max_value() as u64,
@ -78,7 +78,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
location, location,
dst_place, dst_place,
&src_place.base, &src_place.base,
proj, &src_place.projection,
item_ty, item_ty,
size as u32, size as u32,
); );
@ -97,73 +97,76 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
location: Location, location: Location,
dst_place: &Place<'tcx>, dst_place: &Place<'tcx>,
base: &PlaceBase<'tcx>, base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>, proj: &[PlaceElem<'tcx>],
item_ty: &'tcx ty::TyS<'tcx>, item_ty: &'tcx ty::TyS<'tcx>,
size: u32) { size: u32) {
match proj.elem { if let [proj_base @ .., elem] = proj {
// uniforms statements like_10 = move _2[:-1]; match elem {
ProjectionElem::Subslice{from, to} => { // uniforms statements like_10 = move _2[:-1];
self.patch.make_nop(location); ProjectionElem::Subslice{from, to} => {
let temps : Vec<_> = (from..(size-to)).map(|i| { self.patch.make_nop(location);
let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span); let temps : Vec<_> = (*from..(size-*to)).map(|i| {
self.patch.add_statement(location, StatementKind::StorageLive(temp)); 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, self.patch.add_assign(location,
Place::from(temp), dst_place.clone(),
Rvalue::Use( Rvalue::Use(
Operand::Move( Operand::Move(
Place { Place {
base: base.clone(), base: base.clone(),
projection: Some(box Projection { projection: projection.into_boxed_slice(),
base: proj.base.clone(),
elem: ProjectionElem::ConstantIndex {
offset: i,
min_length: size,
from_end: false,
}
}),
} }
) )
) )
); );
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,
},
}),
}
)
)
);
}
_ => {}
} }
} }
} }
@ -197,12 +200,12 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
for candidate in &visitor.candidates { for candidate in &visitor.candidates {
let statement = &body[candidate.block].statements[candidate.statement_index]; let statement = &body[candidate.block].statements[candidate.statement_index];
if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind { if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval { if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
let items : Vec<_> = items.iter().map(|item| { let items : Vec<_> = items.iter().map(|item| {
if let Operand::Move(Place { if let Operand::Move(Place {
base: PlaceBase::Local(local), base: PlaceBase::Local(local),
projection: None, projection: box [],
}) = item { }) = item {
let local_use = &visitor.locals_use[*local]; let local_use = &visitor.locals_use[*local];
let opt_index_and_place = let opt_index_and_place =
@ -269,16 +272,17 @@ impl RestoreSubsliceArrayMoveOut {
} }
patch.make_nop(candidate); patch.make_nop(candidate);
let size = opt_size.unwrap() as u32; let size = opt_size.unwrap() as u32;
patch.add_assign(candidate,
dst_place.clone(), let mut projection = src_place.projection.to_vec();
Rvalue::Use( projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
Operand::Move( patch.add_assign(
Place { candidate,
base: src_place.base.clone(), dst_place.clone(),
projection: Some(box Projection { Rvalue::Use(Operand::Move(Place {
base: src_place.projection.clone(), base: src_place.base.clone(),
elem: ProjectionElem::Subslice{ projection: projection.into_boxed_slice(),
from: min, to: size - max - 1}})}))); })),
);
} }
} }
@ -289,23 +293,34 @@ impl RestoreSubsliceArrayMoveOut {
if block.statements.len() > location.statement_index { if block.statements.len() > location.statement_index {
let statement = &block.statements[location.statement_index]; let statement = &block.statements[location.statement_index];
if let StatementKind::Assign( if let StatementKind::Assign(
Place { box(
base: PlaceBase::Local(_), Place {
projection: None, base: PlaceBase::Local(_),
}, projection: box [],
box Rvalue::Use(Operand::Move(Place { },
base, Rvalue::Use(Operand::Move(Place {
projection: Some(box Projection { base: _,
base: proj_base, projection: box [.., ProjectionElem::ConstantIndex {
elem: ProjectionElem::ConstantIndex {
offset, min_length: _, from_end: false offset, min_length: _, from_end: false
} }],
}), })),
}))) = &statement.kind { )
return Some((*offset, PlaceRef { ) = &statement.kind {
base, // FIXME remove once we can use slices patterns
projection: proj_base, if let StatementKind::Assign(
})) box(
_,
Rvalue::Use(Operand::Move(Place {
base,
projection: box [proj_base @ .., _],
})),
)
) = &statement.kind {
return Some((*offset, PlaceRef {
base,
projection: proj_base,
}))
}
} }
} }
} }

View file

@ -24,7 +24,7 @@ pub fn expand_aggregate<'tcx>(
if adt_def.is_enum() { if adt_def.is_enum() {
set_discriminant = Some(Statement { set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant { kind: StatementKind::SetDiscriminant {
place: lhs.clone(), place: box(lhs.clone()),
variant_index, variant_index,
}, },
source_info, source_info,
@ -39,7 +39,7 @@ pub fn expand_aggregate<'tcx>(
let variant_index = VariantIdx::new(0); let variant_index = VariantIdx::new(0);
set_discriminant = Some(Statement { set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant { kind: StatementKind::SetDiscriminant {
place: lhs.clone(), place: box(lhs.clone()),
variant_index, variant_index,
}, },
source_info, source_info,
@ -70,7 +70,7 @@ pub fn expand_aggregate<'tcx>(
}; };
Statement { Statement {
source_info, source_info,
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)), kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))),
} }
}).chain(set_discriminant) }).chain(set_discriminant)
} }

View file

@ -38,14 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
where where
L: HasLocalDecls<'tcx>, 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 elem {
match proj.elem {
// encountered a Deref, which is ABI-aligned // encountered a Deref, which is ABI-aligned
ProjectionElem::Deref => break, ProjectionElem::Deref => break,
ProjectionElem::Field(..) => { 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 { match ty.sty {
ty::Adt(def, _) if def.repr.packed() => { ty::Adt(def, _) if def.repr.packed() => {
return true return true
@ -55,7 +55,6 @@ where
} }
_ => {} _ => {}
} }
place_projection = &proj.base;
} }
false false

View file

@ -586,10 +586,7 @@ where
BorrowKind::Mut { allow_two_phase_borrow: false }, BorrowKind::Mut { allow_two_phase_borrow: false },
Place { Place {
base: PlaceBase::Local(cur), base: PlaceBase::Local(cur),
projection: Some(Box::new(Projection { projection: Box::new([ProjectionElem::Deref]),
base: None,
elem: ProjectionElem::Deref,
})),
} }
), ),
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one)) Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
@ -981,7 +978,7 @@ where
fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
Statement { Statement {
source_info: self.source_info, source_info: self.source_info,
kind: StatementKind::Assign(lhs.clone(), box rhs) kind: StatementKind::Assign(box(lhs.clone(), rhs))
} }
} }
} }

View file

@ -120,7 +120,7 @@ impl<'tcx> MirPatch<'tcx> {
} }
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) { pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
self.add_statement(loc, StatementKind::Assign(place, box rv)); self.add_statement(loc, StatementKind::Assign(box(place, rv)));
} }
pub fn make_nop(&mut self, loc: Location) { pub fn make_nop(&mut self, loc: Location) {