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:
commit
a6946a817a
61 changed files with 1602 additions and 1788 deletions
|
|
@ -32,7 +32,6 @@ use rustc_serialize::{Encodable, Decodable};
|
|||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||
use std::iter::FusedIterator;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::slice;
|
||||
use std::vec::IntoIter;
|
||||
|
|
@ -1548,7 +1547,7 @@ pub struct Statement<'tcx> {
|
|||
|
||||
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static_assert_size!(Statement<'_>, 56);
|
||||
static_assert_size!(Statement<'_>, 32);
|
||||
|
||||
impl Statement<'_> {
|
||||
/// 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)]
|
||||
pub enum StatementKind<'tcx> {
|
||||
/// 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
|
||||
/// (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
|
||||
/// 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.
|
||||
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.
|
||||
StorageLive(Local),
|
||||
|
|
@ -1598,7 +1597,7 @@ pub enum StatementKind<'tcx> {
|
|||
/// 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/>
|
||||
/// for more details.
|
||||
Retag(RetagKind, Place<'tcx>),
|
||||
Retag(RetagKind, Box<Place<'tcx>>),
|
||||
|
||||
/// Encodes a user's type ascription. These need to be preserved
|
||||
/// intact so that NLL can respect them. For example:
|
||||
|
|
@ -1612,7 +1611,7 @@ pub enum StatementKind<'tcx> {
|
|||
/// - `Contravariant` -- requires that `T_y :> T`
|
||||
/// - `Invariant` -- requires that `T_y == T`
|
||||
/// - `Bivariant` -- no effect
|
||||
AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>),
|
||||
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
|
||||
|
||||
/// No-op. Useful for deleting instructions without affecting statement indices.
|
||||
Nop,
|
||||
|
|
@ -1676,7 +1675,7 @@ impl Debug for Statement<'_> {
|
|||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
use self::StatementKind::*;
|
||||
match self.kind {
|
||||
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
|
||||
Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
|
||||
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
|
||||
Retag(ref kind, ref place) => write!(
|
||||
fmt,
|
||||
|
|
@ -1697,7 +1696,7 @@ impl Debug for Statement<'_> {
|
|||
InlineAsm(ref asm) => {
|
||||
write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
|
||||
}
|
||||
AscribeUserType(ref place, ref variance, ref c_ty) => {
|
||||
AscribeUserType(box(ref place, ref c_ty), ref variance) => {
|
||||
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
||||
}
|
||||
Nop => write!(fmt, "nop"),
|
||||
|
|
@ -1717,7 +1716,7 @@ pub struct Place<'tcx> {
|
|||
pub base: PlaceBase<'tcx>,
|
||||
|
||||
/// projection out of a place (access a field, deref a pointer, etc)
|
||||
pub projection: Option<Box<Projection<'tcx>>>,
|
||||
pub projection: Box<[PlaceElem<'tcx>]>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
|
|
@ -1760,15 +1759,6 @@ impl_stable_hash_for!(struct Static<'tcx> {
|
|||
def_id
|
||||
});
|
||||
|
||||
/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`.
|
||||
#[derive(
|
||||
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
|
||||
)]
|
||||
pub struct Projection<'tcx> {
|
||||
pub base: Option<Box<Projection<'tcx>>>,
|
||||
pub elem: PlaceElem<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
|
||||
)]
|
||||
|
|
@ -1850,14 +1840,22 @@ newtype_index! {
|
|||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PlaceRef<'a, 'tcx> {
|
||||
pub base: &'a PlaceBase<'tcx>,
|
||||
pub projection: &'a Option<Box<Projection<'tcx>>>,
|
||||
pub projection: &'a [PlaceElem<'tcx>],
|
||||
}
|
||||
|
||||
impl<'tcx> Place<'tcx> {
|
||||
pub const RETURN_PLACE: Place<'tcx> = Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: None,
|
||||
};
|
||||
// FIXME change this back to a const when projection is a shared slice.
|
||||
//
|
||||
// pub const RETURN_PLACE: Place<'tcx> = Place {
|
||||
// base: PlaceBase::Local(RETURN_PLACE),
|
||||
// projection: &[],
|
||||
// };
|
||||
pub fn return_place() -> Place<'tcx> {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: Box::new([]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||
self.elem(ProjectionElem::Field(f, ty))
|
||||
|
|
@ -1883,9 +1881,13 @@ impl<'tcx> Place<'tcx> {
|
|||
}
|
||||
|
||||
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
|
||||
// FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
|
||||
let mut projection = self.projection.into_vec();
|
||||
projection.push(elem);
|
||||
|
||||
Place {
|
||||
base: self.base,
|
||||
projection: Some(Box::new(Projection { base: self.projection, elem })),
|
||||
projection: projection.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1894,7 +1896,7 @@ impl<'tcx> Place<'tcx> {
|
|||
/// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
|
||||
/// same region of memory as its base.
|
||||
pub fn is_indirect(&self) -> bool {
|
||||
self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect()))
|
||||
self.projection.iter().any(|elem| elem.is_indirect())
|
||||
}
|
||||
|
||||
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
|
||||
|
|
@ -1905,61 +1907,16 @@ impl<'tcx> Place<'tcx> {
|
|||
match self {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
} => Some(*local),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively "iterates" over place components, generating a `PlaceBase` and
|
||||
/// `Projections` list and invoking `op` with a `ProjectionsIter`.
|
||||
pub fn iterate<R>(
|
||||
&self,
|
||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
||||
) -> R {
|
||||
Place::iterate_over(&self.base, &self.projection, op)
|
||||
}
|
||||
|
||||
pub fn iterate_over<R>(
|
||||
place_base: &PlaceBase<'tcx>,
|
||||
place_projection: &Option<Box<Projection<'tcx>>>,
|
||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
||||
) -> R {
|
||||
fn iterate_over2<'tcx, R>(
|
||||
place_base: &PlaceBase<'tcx>,
|
||||
place_projection: &Option<Box<Projection<'tcx>>>,
|
||||
next: &Projections<'_, 'tcx>,
|
||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
||||
) -> R {
|
||||
match place_projection {
|
||||
None => {
|
||||
op(place_base, next.iter())
|
||||
}
|
||||
|
||||
Some(interior) => {
|
||||
iterate_over2(
|
||||
place_base,
|
||||
&interior.base,
|
||||
&Projections::List {
|
||||
projection: interior,
|
||||
next,
|
||||
},
|
||||
op,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterate_over2(place_base, place_projection, &Projections::Empty, op)
|
||||
}
|
||||
|
||||
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
|
||||
PlaceRef {
|
||||
base: &self.base,
|
||||
|
|
@ -1972,7 +1929,7 @@ impl From<Local> for Place<'_> {
|
|||
fn from(local: Local) -> Self {
|
||||
Place {
|
||||
base: local.into(),
|
||||
projection: None,
|
||||
projection: Box::new([]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1984,13 +1941,6 @@ impl From<Local> for PlaceBase<'_> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
||||
pub fn iterate<R>(
|
||||
&self,
|
||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
||||
) -> R {
|
||||
Place::iterate_over(self.base, self.projection, op)
|
||||
}
|
||||
|
||||
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
|
||||
/// a single deref of a local.
|
||||
//
|
||||
|
|
@ -1999,143 +1949,71 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
|||
match self {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} |
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [ProjectionElem::Deref],
|
||||
} => Some(*local),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A linked list of projections running up the stack; begins with the
|
||||
/// innermost projection and extends to the outermost (e.g., `a.b.c`
|
||||
/// would have the place `b` with a "next" pointer to `b.c`).
|
||||
/// Created by `Place::iterate`.
|
||||
///
|
||||
/// N.B., this particular impl strategy is not the most obvious. It was
|
||||
/// chosen because it makes a measurable difference to NLL
|
||||
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
|
||||
pub enum Projections<'p, 'tcx> {
|
||||
Empty,
|
||||
|
||||
List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> },
|
||||
}
|
||||
|
||||
impl<'p, 'tcx> Projections<'p, 'tcx> {
|
||||
fn iter(&self) -> ProjectionsIter<'_, 'tcx> {
|
||||
ProjectionsIter { value: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> {
|
||||
type Item = &'p Projection<'tcx>;
|
||||
type IntoIter = ProjectionsIter<'p, 'tcx>;
|
||||
|
||||
/// Converts a list of `Projection` components into an iterator;
|
||||
/// this iterator yields up a never-ending stream of `Option<&Place>`.
|
||||
/// These begin with the "innermost" projection and then with each
|
||||
/// projection therefrom. So given a place like `a.b.c` it would
|
||||
/// yield up:
|
||||
///
|
||||
/// ```notrust
|
||||
/// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
|
||||
/// ```
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over components; see `Projections::iter` for more
|
||||
/// information.
|
||||
///
|
||||
/// N.B., this is not a *true* Rust iterator -- the code above just
|
||||
/// manually invokes `next`. This is because we (sometimes) want to
|
||||
/// keep executing even after `None` has been returned.
|
||||
pub struct ProjectionsIter<'p, 'tcx> {
|
||||
pub value: &'p Projections<'p, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> {
|
||||
type Item = &'p Projection<'tcx>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let &Projections::List { projection, next } = self.value {
|
||||
self.value = next;
|
||||
Some(projection)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {}
|
||||
|
||||
impl Debug for Place<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.iterate(|_place_base, place_projections| {
|
||||
// FIXME: remove this collect once we have migrated to slices
|
||||
let projs_vec: Vec<_> = place_projections.collect();
|
||||
for projection in projs_vec.iter().rev() {
|
||||
match projection.elem {
|
||||
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
|
||||
write!(fmt, "(").unwrap();
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, "(*").unwrap();
|
||||
}
|
||||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
for elem in self.projection.iter().rev() {
|
||||
match elem {
|
||||
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
|
||||
write!(fmt, "(").unwrap();
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
write!(fmt, "(*").unwrap();
|
||||
}
|
||||
ProjectionElem::Index(_)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
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| {
|
||||
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(())
|
||||
})
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3120,14 +2998,14 @@ BraceStructTypeFoldableImpl! {
|
|||
|
||||
EnumTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
|
||||
(StatementKind::Assign)(a, b),
|
||||
(StatementKind::Assign)(a),
|
||||
(StatementKind::FakeRead)(cause, place),
|
||||
(StatementKind::SetDiscriminant) { place, variant_index },
|
||||
(StatementKind::StorageLive)(a),
|
||||
(StatementKind::StorageDead)(a),
|
||||
(StatementKind::InlineAsm)(a),
|
||||
(StatementKind::Retag)(kind, place),
|
||||
(StatementKind::AscribeUserType)(a, v, b),
|
||||
(StatementKind::AscribeUserType)(a, v),
|
||||
(StatementKind::Nop),
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
use crate::mir::ProjectionElem::*;
|
||||
|
||||
let base = self.base.fold_with(folder);
|
||||
let elem = match self.elem {
|
||||
match self {
|
||||
Deref => Deref,
|
||||
Field(f, ref ty) => Field(f, ty.fold_with(folder)),
|
||||
Index(ref v) => Index(v.fold_with(folder)),
|
||||
ref elem => elem.clone(),
|
||||
};
|
||||
|
||||
Projection { base, elem }
|
||||
Field(f, ty) => Field(*f, ty.fold_with(folder)),
|
||||
Index(v) => Index(v.fold_with(folder)),
|
||||
elem => elem.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
|
||||
use crate::mir::ProjectionElem::*;
|
||||
|
||||
self.base.visit_with(visitor)
|
||||
|| match self.elem {
|
||||
Field(_, ref ty) => ty.visit_with(visitor),
|
||||
Index(ref v) => v.visit_with(visitor),
|
||||
_ => false,
|
||||
}
|
||||
match self {
|
||||
Field(_, ty) => ty.visit_with(visitor),
|
||||
Index(v) => v.visit_with(visitor),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,21 +121,16 @@ BraceStructTypeFoldableImpl! {
|
|||
impl<'tcx> Place<'tcx> {
|
||||
pub fn ty_from<D>(
|
||||
base: &PlaceBase<'tcx>,
|
||||
projection: &Option<Box<Projection<'tcx>>>,
|
||||
projection: &[PlaceElem<'tcx>],
|
||||
local_decls: &D,
|
||||
tcx: TyCtxt<'tcx>
|
||||
) -> PlaceTy<'tcx>
|
||||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
Place::iterate_over(base, projection, |place_base, place_projections| {
|
||||
let mut place_ty = place_base.ty(local_decls);
|
||||
|
||||
for proj in place_projections {
|
||||
place_ty = place_ty.projection_ty(tcx, &proj.elem);
|
||||
}
|
||||
|
||||
place_ty
|
||||
})
|
||||
projection.iter().fold(
|
||||
base.ty(local_decls),
|
||||
|place_ty, elem| place_ty.projection_ty(tcx, elem)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
|
||||
|
|
|
|||
|
|
@ -152,18 +152,18 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
|
||||
fn visit_place_base(&mut self,
|
||||
place_base: & $($mutability)? PlaceBase<'tcx>,
|
||||
base: & $($mutability)? PlaceBase<'tcx>,
|
||||
context: PlaceContext,
|
||||
location: Location) {
|
||||
self.super_place_base(place_base, context, location);
|
||||
self.super_place_base(base, context, location);
|
||||
}
|
||||
|
||||
fn visit_projection(&mut self,
|
||||
place_base: & $($mutability)? PlaceBase<'tcx>,
|
||||
place: & $($mutability)? Projection<'tcx>,
|
||||
base: & $($mutability)? PlaceBase<'tcx>,
|
||||
projection: & $($mutability)? [PlaceElem<'tcx>],
|
||||
context: PlaceContext,
|
||||
location: Location) {
|
||||
self.super_projection(place_base, place, context, location);
|
||||
self.super_projection(base, projection, context, location);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self,
|
||||
|
|
@ -344,7 +344,9 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
self.visit_source_info(source_info);
|
||||
match kind {
|
||||
StatementKind::Assign(place, rvalue) => {
|
||||
StatementKind::Assign(
|
||||
box(ref $($mutability)? place, ref $($mutability)? rvalue)
|
||||
) => {
|
||||
self.visit_assign(place, rvalue, location);
|
||||
}
|
||||
StatementKind::FakeRead(_, place) => {
|
||||
|
|
@ -391,7 +393,10 @@ macro_rules! make_mir_visitor {
|
|||
StatementKind::Retag(kind, place) => {
|
||||
self.visit_retag(kind, place, location);
|
||||
}
|
||||
StatementKind::AscribeUserType(place, variance, user_ty) => {
|
||||
StatementKind::AscribeUserType(
|
||||
box(ref $($mutability)? place, ref $($mutability)? user_ty),
|
||||
variance
|
||||
) => {
|
||||
self.visit_ascribe_user_ty(place, variance, user_ty, location);
|
||||
}
|
||||
StatementKind::Nop => {}
|
||||
|
|
@ -685,7 +690,7 @@ macro_rules! make_mir_visitor {
|
|||
location: Location) {
|
||||
let mut context = context;
|
||||
|
||||
if place.projection.is_some() {
|
||||
if !place.projection.is_empty() {
|
||||
context = if context.is_mutating_use() {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
|
|
@ -695,9 +700,10 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
self.visit_place_base(& $($mutability)? place.base, context, location);
|
||||
|
||||
if let Some(box proj) = & $($mutability)? place.projection {
|
||||
self.visit_projection(& $($mutability)? place.base, proj, context, location);
|
||||
}
|
||||
self.visit_projection(& $($mutability)? place.base,
|
||||
& $($mutability)? place.projection,
|
||||
context,
|
||||
location);
|
||||
}
|
||||
|
||||
fn super_place_base(&mut self,
|
||||
|
|
@ -715,31 +721,31 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
|
||||
fn super_projection(&mut self,
|
||||
place_base: & $($mutability)? PlaceBase<'tcx>,
|
||||
proj: & $($mutability)? Projection<'tcx>,
|
||||
base: & $($mutability)? PlaceBase<'tcx>,
|
||||
projection: & $($mutability)? [PlaceElem<'tcx>],
|
||||
context: PlaceContext,
|
||||
location: Location) {
|
||||
if let Some(box proj_base) = & $($mutability)? proj.base {
|
||||
self.visit_projection(place_base, proj_base, context, location);
|
||||
}
|
||||
if let [proj_base @ .., elem] = projection {
|
||||
self.visit_projection(base, proj_base, context, location);
|
||||
|
||||
match & $($mutability)? proj.elem {
|
||||
ProjectionElem::Field(_field, ty) => {
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
ProjectionElem::Index(local) => {
|
||||
self.visit_local(
|
||||
local,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
);
|
||||
}
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Subslice { from: _, to: _ } |
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
from_end: _ } |
|
||||
ProjectionElem::Downcast(_, _) => {
|
||||
match elem {
|
||||
ProjectionElem::Field(_field, ty) => {
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
ProjectionElem::Index(local) => {
|
||||
self.visit_local(
|
||||
local,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
);
|
||||
}
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Subslice { from: _, to: _ } |
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
from_end: _ } |
|
||||
ProjectionElem::Downcast(_, _) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(libc)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
) {
|
||||
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.
|
||||
let is_consume = match context {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
|
|
@ -114,12 +114,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
};
|
||||
if is_consume {
|
||||
let base_ty =
|
||||
mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx());
|
||||
mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx());
|
||||
let base_ty = self.fx.monomorphize(&base_ty);
|
||||
|
||||
// ZSTs don't require any actual memory access.
|
||||
let elem_ty = base_ty
|
||||
.projection_ty(cx.tcx(), &proj.elem)
|
||||
.projection_ty(cx.tcx(), elem)
|
||||
.ty;
|
||||
let elem_ty = self.fx.monomorphize(&elem_ty);
|
||||
let span = if let mir::PlaceBase::Local(index) = place_ref.base {
|
||||
|
|
@ -131,7 +131,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
return;
|
||||
}
|
||||
|
||||
if let mir::ProjectionElem::Field(..) = proj.elem {
|
||||
if let mir::ProjectionElem::Field(..) = elem {
|
||||
let layout = cx.spanned_layout_of(base_ty.ty, span);
|
||||
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
|
||||
// Recurse with the same context, instead of `Projection`,
|
||||
|
|
@ -140,7 +140,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
self.process_place(
|
||||
&mir::PlaceRef {
|
||||
base: place_ref.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
context,
|
||||
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.
|
||||
if let mir::ProjectionElem::Deref = proj.elem {
|
||||
if let mir::ProjectionElem::Deref = elem {
|
||||
self.process_place(
|
||||
&mir::PlaceRef {
|
||||
base: place_ref.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
|
|
@ -168,7 +168,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
// visit_place API
|
||||
let mut context = context;
|
||||
|
||||
if place_ref.projection.is_some() {
|
||||
if !place_ref.projection.is_empty() {
|
||||
context = if context.is_mutating_use() {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
|
|
@ -177,10 +177,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
self.visit_place_base(place_ref.base, context, location);
|
||||
|
||||
if let Some(box proj) = place_ref.projection {
|
||||
self.visit_projection(place_ref.base, proj, context, location);
|
||||
}
|
||||
self.visit_projection(place_ref.base, place_ref.projection, context, location);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -196,7 +193,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *place {
|
||||
self.assign(index, location);
|
||||
let decl_span = self.fx.mir.local_decls[index].source_info.span;
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => {
|
||||
let op =
|
||||
self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_ref());
|
||||
self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref());
|
||||
if let Ref(llval, _, align) = op.val {
|
||||
bx.load(llval, align)
|
||||
} else {
|
||||
|
|
@ -612,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}
|
||||
) |
|
||||
mir::Operand::Move(
|
||||
|
|
@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}
|
||||
) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
|
|
@ -1105,7 +1105,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
let dest = if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *dest {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(dest) => dest,
|
||||
|
|
@ -1166,7 +1166,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) {
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *dst {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
||||
|
|
|
|||
|
|
@ -384,47 +384,45 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) -> Option<OperandRef<'tcx, Bx::Value>> {
|
||||
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
|
||||
|
||||
place_ref.iterate(|place_base, place_projection| {
|
||||
if let mir::PlaceBase::Local(index) = place_base {
|
||||
match self.locals[*index] {
|
||||
LocalRef::Operand(Some(mut o)) => {
|
||||
// Moves out of scalar and scalar pair fields are trivial.
|
||||
for proj in place_projection {
|
||||
match proj.elem {
|
||||
mir::ProjectionElem::Field(ref f, _) => {
|
||||
o = o.extract_field(bx, f.index());
|
||||
}
|
||||
mir::ProjectionElem::Index(_) |
|
||||
mir::ProjectionElem::ConstantIndex { .. } => {
|
||||
// ZSTs don't require any actual memory access.
|
||||
// FIXME(eddyb) deduplicate this with the identical
|
||||
// checks in `codegen_consume` and `extract_field`.
|
||||
let elem = o.layout.field(bx.cx(), 0);
|
||||
if elem.is_zst() {
|
||||
o = OperandRef::new_zst(bx, elem);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
if let mir::PlaceBase::Local(index) = place_ref.base {
|
||||
match self.locals[*index] {
|
||||
LocalRef::Operand(Some(mut o)) => {
|
||||
// Moves out of scalar and scalar pair fields are trivial.
|
||||
for elem in place_ref.projection.iter() {
|
||||
match elem {
|
||||
mir::ProjectionElem::Field(ref f, _) => {
|
||||
o = o.extract_field(bx, f.index());
|
||||
}
|
||||
mir::ProjectionElem::Index(_) |
|
||||
mir::ProjectionElem::ConstantIndex { .. } => {
|
||||
// ZSTs don't require any actual memory access.
|
||||
// FIXME(eddyb) deduplicate this with the identical
|
||||
// checks in `codegen_consume` and `extract_field`.
|
||||
let elem = o.layout.field(bx.cx(), 0);
|
||||
if elem.is_zst() {
|
||||
o = OperandRef::new_zst(bx, elem);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
Some(o)
|
||||
}
|
||||
LocalRef::Operand(None) => {
|
||||
bug!("use of {:?} before def", place_ref);
|
||||
}
|
||||
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
|
||||
// watch out for locals that do not have an
|
||||
// alloca; they are handled somewhat differently
|
||||
None
|
||||
}
|
||||
Some(o)
|
||||
}
|
||||
LocalRef::Operand(None) => {
|
||||
bug!("use of {:?} before def", place_ref);
|
||||
}
|
||||
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
|
||||
// watch out for locals that do not have an
|
||||
// alloca; they are handled somewhat differently
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_consume(
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let result = match &place_ref {
|
||||
mir::PlaceRef {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
match self.locals[*index] {
|
||||
LocalRef::Place(place) => {
|
||||
|
|
@ -469,7 +469,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
kind: mir::StaticKind::Promoted(promoted, substs),
|
||||
def_id,
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let instance = Instance::new(*def_id, self.monomorphize(substs));
|
||||
|
|
@ -504,7 +504,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
kind: mir::StaticKind::Static,
|
||||
def_id,
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
// NB: The layout of a static may be unsized as is the case when working
|
||||
// with a static that is an extern_type.
|
||||
|
|
@ -514,10 +514,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
},
|
||||
mir::PlaceRef {
|
||||
base,
|
||||
projection: Some(box mir::Projection {
|
||||
base: proj_base,
|
||||
elem: mir::ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [proj_base @ .., mir::ProjectionElem::Deref],
|
||||
} => {
|
||||
// Load the pointer from its location.
|
||||
self.codegen_consume(bx, &mir::PlaceRef {
|
||||
|
|
@ -527,22 +524,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
mir::PlaceRef {
|
||||
base,
|
||||
projection: Some(projection),
|
||||
projection: [proj_base @ .., elem],
|
||||
} => {
|
||||
// FIXME turn this recursion into iteration
|
||||
let cg_base = self.codegen_place(bx, &mir::PlaceRef {
|
||||
base,
|
||||
projection: &projection.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
|
||||
match projection.elem {
|
||||
match elem {
|
||||
mir::ProjectionElem::Deref => bug!(),
|
||||
mir::ProjectionElem::Field(ref field, _) => {
|
||||
cg_base.project_field(bx, field.index())
|
||||
}
|
||||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Copy(
|
||||
mir::Place::from(index)
|
||||
mir::Place::from(*index)
|
||||
);
|
||||
let index = self.codegen_operand(bx, index);
|
||||
let llindex = index.immediate();
|
||||
|
|
@ -551,27 +548,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: false,
|
||||
min_length: _ } => {
|
||||
let lloffset = bx.cx().const_usize(offset as u64);
|
||||
let lloffset = bx.cx().const_usize(*offset as u64);
|
||||
cg_base.project_index(bx, lloffset)
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: true,
|
||||
min_length: _ } => {
|
||||
let lloffset = bx.cx().const_usize(offset as u64);
|
||||
let lloffset = bx.cx().const_usize(*offset as u64);
|
||||
let lllen = cg_base.len(bx.cx());
|
||||
let llindex = bx.sub(lllen, lloffset);
|
||||
cg_base.project_index(bx, llindex)
|
||||
}
|
||||
mir::ProjectionElem::Subslice { from, to } => {
|
||||
let mut subslice = cg_base.project_index(bx,
|
||||
bx.cx().const_usize(from as u64));
|
||||
bx.cx().const_usize(*from as u64));
|
||||
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
|
||||
.projection_ty(tcx, &projection.elem).ty;
|
||||
.projection_ty(tcx, elem).ty;
|
||||
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
|
||||
|
||||
if subslice.layout.is_unsized() {
|
||||
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
|
||||
bx.cx().const_usize((from as u64) + (to as u64))));
|
||||
bx.cx().const_usize((*from as u64) + (*to as u64))));
|
||||
}
|
||||
|
||||
// Cast the place pointer type to the new
|
||||
|
|
@ -582,7 +579,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
subslice
|
||||
}
|
||||
mir::ProjectionElem::Downcast(_, v) => {
|
||||
cg_base.project_downcast(bx, v)
|
||||
cg_base.project_downcast(bx, *v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -522,7 +522,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// because codegen_place() panics if Local is operand.
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||
if let ty::Array(_, n) = op.layout.ty.sty {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
self.set_debug_loc(&mut bx, statement.source_info);
|
||||
match statement.kind {
|
||||
mir::StatementKind::Assign(ref place, ref rvalue) => {
|
||||
mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
} = *place {
|
||||
match self.locals[index] {
|
||||
projection: box [],
|
||||
} = place {
|
||||
match self.locals[*index] {
|
||||
LocalRef::Place(cg_dest) => {
|
||||
self.codegen_rvalue(bx, cg_dest, rvalue)
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
LocalRef::Operand(None) => {
|
||||
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
|
||||
if let Some(name) = self.mir.local_decls[index].name {
|
||||
if let Some(name) = self.mir.local_decls[*index].name {
|
||||
match operand.val {
|
||||
OperandValue::Ref(x, ..) |
|
||||
OperandValue::Immediate(x) => {
|
||||
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.locals[index] = LocalRef::Operand(Some(operand));
|
||||
self.locals[*index] = LocalRef::Operand(Some(operand));
|
||||
bx
|
||||
}
|
||||
LocalRef::Operand(Some(op)) => {
|
||||
|
|
@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.codegen_rvalue(bx, cg_dest, rvalue)
|
||||
}
|
||||
}
|
||||
mir::StatementKind::SetDiscriminant{ref place, variant_index} => {
|
||||
mir::StatementKind::SetDiscriminant{box ref place, variant_index} => {
|
||||
self.codegen_place(&mut bx, &place.as_ref())
|
||||
.codegen_set_discr(&mut bx, variant_index);
|
||||
bx
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
|||
// so extract `temp`.
|
||||
let temp = if let &mir::Place {
|
||||
base: mir::PlaceBase::Local(temp),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = assigned_place {
|
||||
temp
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use rustc::hir;
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
|
||||
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
|
||||
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
|
||||
Statement, StatementKind, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -244,7 +244,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
let span = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = place {
|
||||
let decl = &self.body.local_decls[*local];
|
||||
Some(decl.source_info.span)
|
||||
|
|
@ -614,17 +614,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
projection,
|
||||
} = 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 {
|
||||
ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => {
|
||||
ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
|
||||
return Some((PlaceRef {
|
||||
base: base,
|
||||
projection: base_proj,
|
||||
projection: proj_base,
|
||||
}, field));
|
||||
},
|
||||
_ => current = base_proj,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
@ -637,9 +637,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
projection,
|
||||
} = second_borrowed_place;
|
||||
|
||||
let mut current = projection;
|
||||
for (i, elem) in projection.iter().enumerate().rev() {
|
||||
let proj_base = &projection[..i];
|
||||
|
||||
while let Some(box Projection { base: proj_base, elem }) = current {
|
||||
if let ProjectionElem::Field(field, _) = elem {
|
||||
if let Some(union_ty) = union_ty(base, proj_base) {
|
||||
if field != target_field
|
||||
|
|
@ -660,8 +660,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
current = proj_base;
|
||||
}
|
||||
None
|
||||
})
|
||||
|
|
@ -707,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.var_or_use();
|
||||
|
||||
assert!(root_place.projection.is_none());
|
||||
assert!(root_place.projection.is_empty());
|
||||
let proper_span = match root_place.base {
|
||||
PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
|
||||
_ => drop_span,
|
||||
|
|
@ -716,7 +714,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if self.access_place_error_reported
|
||||
.contains(&(Place {
|
||||
base: root_place.base.clone(),
|
||||
projection: root_place.projection.clone(),
|
||||
projection: root_place.projection.to_vec().into_boxed_slice(),
|
||||
}, borrow_span))
|
||||
{
|
||||
debug!(
|
||||
|
|
@ -729,7 +727,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.access_place_error_reported
|
||||
.insert((Place {
|
||||
base: root_place.base.clone(),
|
||||
projection: root_place.projection.clone(),
|
||||
projection: root_place.projection.to_vec().into_boxed_slice(),
|
||||
}, borrow_span));
|
||||
|
||||
if let StorageDeadOrDrop::Destructor(dropped_ty) =
|
||||
|
|
@ -1107,7 +1105,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let local_kind = match borrow.borrowed_place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} => {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer
|
||||
|
|
@ -1136,7 +1134,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.unwrap();
|
||||
let local = if let PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} = root_place {
|
||||
local
|
||||
} else {
|
||||
|
|
@ -1446,7 +1444,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
) {
|
||||
let (from_arg, local_decl) = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *err_place {
|
||||
if let LocalKind::Arg = self.body.local_kind(local) {
|
||||
(true, Some(&self.body.local_decls[local]))
|
||||
|
|
@ -1519,20 +1517,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
match place.projection {
|
||||
None => {
|
||||
[] => {
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
}
|
||||
Some(box Projection { ref base, ref elem }) => {
|
||||
[proj_base @ .., elem] => {
|
||||
// FIXME(spastorino) make this iterate
|
||||
let base_access = self.classify_drop_access_kind(PlaceRef {
|
||||
base: place.base,
|
||||
projection: base,
|
||||
projection: proj_base,
|
||||
});
|
||||
match elem {
|
||||
ProjectionElem::Deref => match base_access {
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
| StorageDeadOrDrop::BoxedStorageDead => {
|
||||
assert!(
|
||||
Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(),
|
||||
Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(),
|
||||
"Drop of value behind a reference or raw pointer"
|
||||
);
|
||||
StorageDeadOrDrop::BoxedStorageDead
|
||||
|
|
@ -1540,7 +1539,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
StorageDeadOrDrop::Destructor(_) => base_access,
|
||||
},
|
||||
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
|
||||
let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
|
||||
match base_ty.sty {
|
||||
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
||||
// Report the outermost adt with a destructor
|
||||
|
|
@ -1598,7 +1597,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"annotate_argument_and_return_for_borrow: location={:?}",
|
||||
location
|
||||
);
|
||||
if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
|
||||
if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
|
||||
= &self.body[location.block].statements.get(location.statement_index)
|
||||
{
|
||||
debug!(
|
||||
|
|
@ -1609,7 +1608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let mut target = *match reservation {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} if self.body.local_kind(*local) == LocalKind::Temp => local,
|
||||
_ => return None,
|
||||
};
|
||||
|
|
@ -1623,11 +1622,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
target, stmt
|
||||
);
|
||||
if let StatementKind::Assign(
|
||||
Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: None,
|
||||
},
|
||||
box rvalue
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: box [],
|
||||
},
|
||||
rvalue
|
||||
)
|
||||
) = &stmt.kind {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
|
|
@ -1753,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let TerminatorKind::Call {
|
||||
destination: Some((Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}, _)),
|
||||
args,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let mut target = place.local_or_deref_local();
|
||||
for stmt in &self.body[location.block].statements[location.statement_index..] {
|
||||
debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
|
||||
if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind {
|
||||
if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
|
||||
debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
|
||||
match from {
|
||||
Operand::Copy(ref place) |
|
||||
|
|
@ -152,7 +152,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match place {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
self.append_local_to_string(*local, buf)?;
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
buf.push_str("promoted");
|
||||
}
|
||||
|
|
@ -173,15 +173,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
def_id,
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
|
||||
}
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: Some(ref proj),
|
||||
projection: [proj_base @ .., elem],
|
||||
} => {
|
||||
match proj.elem {
|
||||
match elem {
|
||||
ProjectionElem::Deref => {
|
||||
let upvar_field_projection =
|
||||
self.is_upvar_field_projection(place);
|
||||
|
|
@ -199,20 +199,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
)?;
|
||||
} else {
|
||||
match (&proj.base, base) {
|
||||
(None, PlaceBase::Local(local)) => {
|
||||
match (proj_base, base) {
|
||||
([], PlaceBase::Local(local)) => {
|
||||
if self.body.local_decls[*local].is_ref_for_guard() {
|
||||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
|
|
@ -224,7 +224,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
|
|
@ -238,7 +238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
|
|
@ -253,7 +253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
|
|
@ -275,12 +275,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} else {
|
||||
let field_name = self.describe_field(PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
}, field);
|
||||
projection: proj_base,
|
||||
}, *field);
|
||||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
|
|
@ -295,14 +295,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
)?;
|
||||
buf.push_str("[");
|
||||
if self.append_local_to_string(index, buf).is_err() {
|
||||
if self.append_local_to_string(*index, buf).is_err() {
|
||||
buf.push_str("_");
|
||||
}
|
||||
buf.push_str("]");
|
||||
|
|
@ -315,7 +315,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.append_place_to_string(
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
|
|
@ -349,28 +349,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match place {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
let local = &self.body.local_decls[*local];
|
||||
self.describe_field_from_ty(&local.ty, field, None)
|
||||
}
|
||||
PlaceRef {
|
||||
base: PlaceBase::Static(static_),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} =>
|
||||
self.describe_field_from_ty(&static_.ty, field, None),
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: Some(proj),
|
||||
} => match proj.elem {
|
||||
ProjectionElem::Deref => self.describe_field(PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
}, field),
|
||||
projection: [proj_base @ .., elem],
|
||||
} => match elem {
|
||||
ProjectionElem::Deref => {
|
||||
self.describe_field(PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}, field)
|
||||
}
|
||||
ProjectionElem::Downcast(_, variant_index) => {
|
||||
let base_ty =
|
||||
Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty;
|
||||
self.describe_field_from_ty(&base_ty, field, Some(variant_index))
|
||||
self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
|
||||
}
|
||||
ProjectionElem::Field(_, field_type) => {
|
||||
self.describe_field_from_ty(&field_type, field, None)
|
||||
|
|
@ -380,7 +382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
| ProjectionElem::Subslice { .. } => {
|
||||
self.describe_field(PlaceRef {
|
||||
base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
}, field)
|
||||
}
|
||||
},
|
||||
|
|
@ -445,7 +447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
def_id,
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} = place_ref {
|
||||
let attrs = self.infcx.tcx.get_attrs(*def_id);
|
||||
let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
|
||||
|
|
@ -790,8 +792,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
||||
if let StatementKind::Assign(
|
||||
_,
|
||||
box Rvalue::Aggregate(ref kind, ref places)
|
||||
box(_, Rvalue::Aggregate(ref kind, ref places))
|
||||
) = stmt.kind {
|
||||
let (def_id, is_generator) = match kind {
|
||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||
|
|
@ -828,10 +829,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.get(location.statement_index)
|
||||
{
|
||||
Some(&Statement {
|
||||
kind: StatementKind::Assign(Place {
|
||||
kind: StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
}, _),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
..
|
||||
}) => local,
|
||||
_ => 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..] {
|
||||
if let StatementKind::Assign(
|
||||
_, box Rvalue::Aggregate(ref kind, ref places)
|
||||
box(_, Rvalue::Aggregate(ref kind, ref places))
|
||||
) = stmt.kind {
|
||||
let (def_id, is_generator) = match kind {
|
||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
|
|||
use rustc::middle::borrowck::SignalledError;
|
||||
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||
use rustc::mir::{
|
||||
ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef,
|
||||
Static, StaticKind
|
||||
ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem,
|
||||
PlaceRef, Static, StaticKind
|
||||
};
|
||||
use rustc::mir::{Field, Projection, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
||||
use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
||||
use rustc::mir::{Terminator, TerminatorKind};
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
|
|
@ -546,7 +546,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
|
|||
self.check_activations(location, span, flow_state);
|
||||
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(ref lhs, ref rhs) => {
|
||||
StatementKind::Assign(box(ref lhs, ref rhs)) => {
|
||||
self.consume_rvalue(
|
||||
location,
|
||||
(rhs, span),
|
||||
|
|
@ -561,7 +561,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
|
|||
flow_state,
|
||||
);
|
||||
}
|
||||
StatementKind::FakeRead(_, ref place) => {
|
||||
StatementKind::FakeRead(_, box ref place) => {
|
||||
// Read for match doesn't access any memory and is used to
|
||||
// assert that a place is safe and live. So we don't have to
|
||||
// do any checks here.
|
||||
|
|
@ -905,7 +905,7 @@ enum InitializationRequiringAction {
|
|||
|
||||
struct RootPlace<'d, 'tcx> {
|
||||
place_base: &'d PlaceBase<'tcx>,
|
||||
place_projection: &'d Option<Box<Projection<'tcx>>>,
|
||||
place_projection: &'d [PlaceElem<'tcx>],
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
}
|
||||
|
||||
|
|
@ -1191,7 +1191,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// before (at this point in the flow).
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = place_span.0 {
|
||||
if let Mutability::Not = self.body.local_decls[*local].mutability {
|
||||
// check for reassignments to immutable local variables
|
||||
|
|
@ -1331,7 +1331,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
|
||||
let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
|
||||
if place.projection.is_some() {
|
||||
if !place.projection.is_empty() {
|
||||
if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
|
||||
this.used_mut_upvars.push(field);
|
||||
}
|
||||
|
|
@ -1346,11 +1346,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match *operand {
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||
// The variable will be marked as mutable by the borrow.
|
||||
|
|
@ -1387,7 +1387,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let stmt = &bbd.statements[loc.statement_index];
|
||||
debug!("temporary assigned in: stmt={:?}", stmt);
|
||||
|
||||
if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind {
|
||||
if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
|
||||
propagate_closure_used_mut_place(self, source);
|
||||
} else {
|
||||
bug!("closures should only capture user variables \
|
||||
|
|
@ -1468,7 +1468,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
|
||||
assert!(root_place.projection.is_none());
|
||||
assert!(root_place.projection.is_empty());
|
||||
let (might_be_alive, will_be_dropped) = match root_place.base {
|
||||
PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
|
|
@ -1756,13 +1756,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
flow_state: &Flows<'cx, 'tcx>,
|
||||
) {
|
||||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||
// recur down place; dispatch to external checks when necessary
|
||||
let mut place_projection = &place.projection;
|
||||
|
||||
// None case => assigning to `x` does not require `x` be initialized.
|
||||
while let Some(proj) = place_projection {
|
||||
let Projection { ref base, ref elem } = **proj;
|
||||
match *elem {
|
||||
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||
match elem {
|
||||
ProjectionElem::Index(_/*operand*/) |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
// assigning to P[i] requires P to be valid.
|
||||
|
|
@ -1774,11 +1771,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
// assigning to (*P) requires P to be initialized
|
||||
ProjectionElem::Deref => {
|
||||
let proj_base = &place.projection[..i];
|
||||
|
||||
self.check_if_full_path_is_moved(
|
||||
location, InitializationRequiringAction::Use,
|
||||
(PlaceRef {
|
||||
base: &place.base,
|
||||
projection: base,
|
||||
projection: proj_base,
|
||||
}, span), flow_state);
|
||||
// (base initialized; no need to
|
||||
// recur further)
|
||||
|
|
@ -1791,18 +1790,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
ProjectionElem::Field(..) => {
|
||||
let proj_base = &place.projection[..i];
|
||||
// if type of `P` has a dtor, then
|
||||
// assigning to `P.f` requires `P` itself
|
||||
// be already initialized
|
||||
let tcx = self.infcx.tcx;
|
||||
let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
|
||||
match base_ty.sty {
|
||||
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
location, InitializationRequiringAction::Assignment,
|
||||
(PlaceRef {
|
||||
base: &place.base,
|
||||
projection: base,
|
||||
projection: proj_base,
|
||||
}, span), flow_state);
|
||||
|
||||
// (base initialized; no need to
|
||||
|
|
@ -1815,7 +1815,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
ty::Adt(..) | ty::Tuple(..) => {
|
||||
check_parent_of_field(self, location, PlaceRef {
|
||||
base: &place.base,
|
||||
projection: base,
|
||||
projection: proj_base,
|
||||
}, span, flow_state);
|
||||
|
||||
if let PlaceBase::Local(local) = place.base {
|
||||
|
|
@ -1835,8 +1835,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
place_projection = base;
|
||||
}
|
||||
|
||||
fn check_parent_of_field<'cx, 'tcx>(
|
||||
|
|
@ -2084,7 +2082,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match root_place {
|
||||
RootPlace {
|
||||
place_base: PlaceBase::Local(local),
|
||||
place_projection: None,
|
||||
place_projection: [],
|
||||
is_local_mutation_allowed,
|
||||
} => {
|
||||
// If the local may have been initialized, and it is now currently being
|
||||
|
|
@ -2103,7 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} => {}
|
||||
RootPlace {
|
||||
place_base,
|
||||
place_projection: place_projection @ Some(_),
|
||||
place_projection: place_projection @ [.., _],
|
||||
is_local_mutation_allowed: _,
|
||||
} => {
|
||||
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
||||
|
|
@ -2115,7 +2113,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
RootPlace {
|
||||
place_base: PlaceBase::Static(..),
|
||||
place_projection: None,
|
||||
place_projection: [],
|
||||
is_local_mutation_allowed: _,
|
||||
} => {}
|
||||
}
|
||||
|
|
@ -2131,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match place {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
let local = &self.body.local_decls[*local];
|
||||
match local.mutability {
|
||||
|
|
@ -2162,7 +2160,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} =>
|
||||
Ok(RootPlace {
|
||||
place_base: place.base,
|
||||
|
|
@ -2175,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
def_id,
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
if !self.infcx.tcx.is_mutable_static(*def_id) {
|
||||
Err(place)
|
||||
|
|
@ -2189,12 +2187,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection: Some(proj),
|
||||
projection: [proj_base @ .., elem],
|
||||
} => {
|
||||
match proj.elem {
|
||||
match elem {
|
||||
ProjectionElem::Deref => {
|
||||
let base_ty =
|
||||
Place::ty_from(place.base, &proj.base, self.body, self.infcx.tcx).ty;
|
||||
Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty;
|
||||
|
||||
// Check the kind of deref to decide
|
||||
match base_ty.sty {
|
||||
|
|
@ -2216,7 +2214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
self.is_mutable(PlaceRef {
|
||||
base: place.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
}, mode)
|
||||
}
|
||||
}
|
||||
|
|
@ -2240,7 +2238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
_ if base_ty.is_box() => {
|
||||
self.is_mutable(PlaceRef {
|
||||
base: place.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
}, is_local_mutation_allowed)
|
||||
}
|
||||
// Deref should only be for reference, pointers or boxes
|
||||
|
|
@ -2297,7 +2295,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// ```
|
||||
let _ = self.is_mutable(PlaceRef {
|
||||
base: place.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
}, is_local_mutation_allowed)?;
|
||||
Ok(RootPlace {
|
||||
place_base: place.base,
|
||||
|
|
@ -2309,7 +2307,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} else {
|
||||
self.is_mutable(PlaceRef {
|
||||
base: place.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
}, is_local_mutation_allowed)
|
||||
}
|
||||
}
|
||||
|
|
@ -2326,21 +2324,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let mut place_projection = place_ref.projection;
|
||||
let mut by_ref = false;
|
||||
|
||||
if let Some(box Projection {
|
||||
base,
|
||||
elem: ProjectionElem::Deref,
|
||||
}) = place_projection {
|
||||
place_projection = &base;
|
||||
if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
|
||||
place_projection = proj_base;
|
||||
by_ref = true;
|
||||
}
|
||||
|
||||
match place_projection {
|
||||
Some(box Projection {
|
||||
base,
|
||||
elem: ProjectionElem::Field(field, _ty),
|
||||
}) => {
|
||||
[base @ .., ProjectionElem::Field(field, _ty)] => {
|
||||
let tcx = self.infcx.tcx;
|
||||
let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty;
|
||||
let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty;
|
||||
|
||||
if (base_ty.is_closure() || base_ty.is_generator()) &&
|
||||
(!by_ref || self.upvars[field.index()].by_ref) {
|
||||
|
|
|
|||
|
|
@ -89,11 +89,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// If that ever stops being the case, then the ever initialized
|
||||
// flow could be used.
|
||||
if let Some(StatementKind::Assign(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
},
|
||||
box Rvalue::Use(Operand::Move(move_from)),
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(move_from))
|
||||
)
|
||||
)) = self.body.basic_blocks()[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
|
|
@ -274,16 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
span: Span
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let description = if place.projection.is_none() {
|
||||
let description = if place.projection.is_empty() {
|
||||
format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
|
||||
} else {
|
||||
let mut base_static = &place.projection;
|
||||
while let Some(box Projection { base: Some(ref proj), .. }) = base_static {
|
||||
base_static = &proj.base;
|
||||
}
|
||||
let base_static = PlaceRef {
|
||||
base: &place.base,
|
||||
projection: base_static,
|
||||
projection: &place.projection[..1],
|
||||
};
|
||||
|
||||
format!(
|
||||
|
|
@ -309,17 +307,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
|
||||
.find_map(|p| self.is_upvar_field_projection(p));
|
||||
|
||||
let deref_base = match deref_target_place.projection {
|
||||
Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef {
|
||||
base: &deref_target_place.base,
|
||||
projection: base,
|
||||
},
|
||||
let deref_base = match &deref_target_place.projection {
|
||||
box [proj_base @ .., ProjectionElem::Deref] => {
|
||||
PlaceRef {
|
||||
base: &deref_target_place.base,
|
||||
projection: proj_base,
|
||||
}
|
||||
}
|
||||
_ => bug!("deref_target_place is not a deref projection"),
|
||||
};
|
||||
|
||||
if let PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} = deref_base {
|
||||
let decl = &self.body.local_decls[*local];
|
||||
if decl.is_ref_for_guard() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc::hir;
|
|||
use rustc::hir::Node;
|
||||
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
|
||||
use rustc::mir::{
|
||||
Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind
|
||||
Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind
|
||||
};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
|
@ -47,12 +47,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
match the_place_err {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
if let Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = access_place {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
|
|
@ -65,14 +65,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection:
|
||||
Some(box Projection {
|
||||
base,
|
||||
elem: ProjectionElem::Field(upvar_index, _),
|
||||
}),
|
||||
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
} => {
|
||||
debug_assert!(is_closure_or_generator(
|
||||
Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty
|
||||
Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty
|
||||
));
|
||||
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
|
|
@ -86,14 +82,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection:
|
||||
Some(box Projection {
|
||||
base,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [proj_base @ .., ProjectionElem::Deref],
|
||||
} => {
|
||||
if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
|
||||
base.is_none() &&
|
||||
proj_base.is_empty() &&
|
||||
!self.upvars.is_empty() {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
|
||||
|
|
@ -114,7 +106,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
", as `Fn` closures cannot mutate their captured variables".to_string()
|
||||
}
|
||||
} else if {
|
||||
if let (PlaceBase::Local(local), 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()
|
||||
} else {
|
||||
false
|
||||
|
|
@ -125,7 +117,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
let source = self.borrowed_content_source(PlaceRef {
|
||||
base: the_place_err.base,
|
||||
projection: base,
|
||||
projection: proj_base,
|
||||
});
|
||||
let pointer_type = source.describe_for_immutable_place();
|
||||
opt_source = Some(source);
|
||||
|
|
@ -151,7 +143,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => unreachable!(),
|
||||
|
||||
PlaceRef {
|
||||
|
|
@ -161,11 +153,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
def_id,
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
if let Place {
|
||||
base: PlaceBase::Static(_),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = access_place {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
reason = String::new();
|
||||
|
|
@ -178,33 +170,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection:
|
||||
Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Index(_),
|
||||
}),
|
||||
projection: [.., ProjectionElem::Index(_)],
|
||||
}
|
||||
| PlaceRef {
|
||||
base: _,
|
||||
projection:
|
||||
Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::ConstantIndex { .. },
|
||||
}),
|
||||
projection: [.., ProjectionElem::ConstantIndex { .. }],
|
||||
}
|
||||
| PlaceRef {
|
||||
base: _,
|
||||
projection: Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Subslice { .. },
|
||||
}),
|
||||
projection: [.., ProjectionElem::Subslice { .. }],
|
||||
}
|
||||
| PlaceRef {
|
||||
base: _,
|
||||
projection: Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Downcast(..),
|
||||
}),
|
||||
projection: [.., ProjectionElem::Downcast(..)],
|
||||
} => bug!("Unexpected immutable place."),
|
||||
}
|
||||
|
||||
|
|
@ -262,22 +240,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// after the field access).
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: Some(box Projection {
|
||||
base: Some(box Projection {
|
||||
base: Some(box Projection {
|
||||
base: base_proj,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
elem: ProjectionElem::Field(field, _),
|
||||
}),
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [proj_base @ ..,
|
||||
ProjectionElem::Deref,
|
||||
ProjectionElem::Field(field, _),
|
||||
ProjectionElem::Deref,
|
||||
],
|
||||
} => {
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
|
||||
if let Some((span, message)) = annotate_struct_field(
|
||||
self.infcx.tcx,
|
||||
Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty,
|
||||
Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty,
|
||||
field,
|
||||
) {
|
||||
err.span_suggestion(
|
||||
|
|
@ -292,7 +265,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// Suggest removing a `&mut` from the use of a mutable reference.
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} if {
|
||||
self.body.local_decls.get(*local).map(|local_decl| {
|
||||
if let ClearCrossCrate::Set(
|
||||
|
|
@ -328,7 +301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// variable) mutations...
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} if self.body.local_decls[*local].can_be_made_mutable() => {
|
||||
// ... but it doesn't make sense to suggest it on
|
||||
// variables that are `ref x`, `ref mut x`, `&self`,
|
||||
|
|
@ -349,13 +322,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// Also suggest adding mut for upvars
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: Some(box Projection {
|
||||
base: proj_base,
|
||||
elem: ProjectionElem::Field(upvar_index, _),
|
||||
}),
|
||||
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
} => {
|
||||
debug_assert!(is_closure_or_generator(
|
||||
Place::ty_from(&base, &proj_base, self.body, self.infcx.tcx).ty
|
||||
Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty
|
||||
));
|
||||
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
|
|
@ -385,7 +355,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// a local variable, then just suggest the user remove it.
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} if {
|
||||
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
snippet.starts_with("&mut ")
|
||||
|
|
@ -400,10 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [ProjectionElem::Deref],
|
||||
} if {
|
||||
if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
|
||||
self.body.local_decls[*local].is_user_variable
|
||||
|
|
@ -427,10 +394,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// arbitrary base for the projection?
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [ProjectionElem::Deref],
|
||||
} if self.body.local_decls[*local].is_user_variable.is_some() =>
|
||||
{
|
||||
let local_decl = &self.body.local_decls[*local];
|
||||
|
|
@ -510,10 +474,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
PlaceRef {
|
||||
base,
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [ProjectionElem::Deref],
|
||||
// FIXME document what is this 1 magic number about
|
||||
} if *base == PlaceBase::Local(Local::new(1)) &&
|
||||
!self.upvars.is_empty() =>
|
||||
|
|
@ -527,10 +488,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection: Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: [.., ProjectionElem::Deref],
|
||||
} => {
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ use rustc::infer::InferCtxt;
|
|||
use rustc::mir::visit::TyContext;
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::{
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
|
||||
ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
UserTypeProjection,
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
|
||||
|
|
@ -229,14 +228,11 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
} => {
|
||||
debug!(
|
||||
"Recording `killed` facts for borrows of local={:?} at location={:?}",
|
||||
|
|
@ -261,7 +257,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(_),
|
||||
projection: box [.., _],
|
||||
} => {
|
||||
// Kill conflicting borrows of the innermost local.
|
||||
debug!(
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||
if let Place {
|
||||
base: PlaceBase::Local(borrowed_local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = place {
|
||||
if body.local_decls[*borrowed_local].name.is_some()
|
||||
&& local != *borrowed_local
|
||||
|
|
@ -495,11 +495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Operand::Constant(c) => c.span,
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) => {
|
||||
let local_decl = &self.body.local_decls[*l];
|
||||
if local_decl.name.is_none() {
|
||||
|
|
@ -541,10 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// it which simplifies the termination logic.
|
||||
let mut queue = vec![location];
|
||||
let mut target = if let Some(&Statement {
|
||||
kind: StatementKind::Assign(Place {
|
||||
kind: StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
}, _),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
..
|
||||
}) = stmt
|
||||
{
|
||||
|
|
@ -567,7 +567,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("was_captured_by_trait_object: stmt={:?}", stmt);
|
||||
|
||||
// The only kind of statement that we care about is assignments...
|
||||
if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
|
||||
if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
|
||||
let into = match place.local_or_deref_local() {
|
||||
Some(into) => into,
|
||||
None => {
|
||||
|
|
@ -583,11 +583,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
})
|
||||
if *from == target =>
|
||||
{
|
||||
|
|
@ -602,11 +602,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
) => match operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
})
|
||||
if *from == target =>
|
||||
{
|
||||
|
|
@ -639,7 +639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let TerminatorKind::Call {
|
||||
destination: Some((Place {
|
||||
base: PlaceBase::Local(dest),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}, block)),
|
||||
args,
|
||||
..
|
||||
|
|
@ -653,7 +653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let found_target = args.iter().any(|arg| {
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(potential),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) = arg {
|
||||
*potential == target
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
self.check_activations(location);
|
||||
|
||||
match statement.kind {
|
||||
StatementKind::Assign(ref lhs, ref rhs) => {
|
||||
StatementKind::Assign(box(ref lhs, ref rhs)) => {
|
||||
self.consume_rvalue(
|
||||
location,
|
||||
rhs,
|
||||
|
|
|
|||
|
|
@ -421,107 +421,104 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
) -> PlaceTy<'tcx> {
|
||||
debug!("sanitize_place: {:?}", place);
|
||||
|
||||
place.iterate(|place_base, place_projection| {
|
||||
let mut place_ty = match place_base {
|
||||
PlaceBase::Local(index) =>
|
||||
PlaceTy::from_ty(self.body.local_decls[*index].ty),
|
||||
PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let check_err =
|
||||
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|
||||
place: &Place<'tcx>,
|
||||
ty,
|
||||
sty| {
|
||||
if let Err(terr) = verifier.cx.eq_types(
|
||||
sty,
|
||||
ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
verifier,
|
||||
place,
|
||||
"bad promoted type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
let mut place_ty = match &place.base {
|
||||
PlaceBase::Local(index) =>
|
||||
PlaceTy::from_ty(self.body.local_decls[*index].ty),
|
||||
PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let check_err =
|
||||
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|
||||
place: &Place<'tcx>,
|
||||
ty,
|
||||
sty| {
|
||||
if let Err(terr) = verifier.cx.eq_types(
|
||||
sty,
|
||||
ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
verifier,
|
||||
place,
|
||||
"bad promoted type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
match kind {
|
||||
StaticKind::Promoted(promoted, _) => {
|
||||
if !self.errors_reported {
|
||||
let promoted_body = &self.promoted[*promoted];
|
||||
self.sanitize_promoted(promoted_body, location);
|
||||
};
|
||||
match kind {
|
||||
StaticKind::Promoted(promoted, _) => {
|
||||
if !self.errors_reported {
|
||||
let promoted_body = &self.promoted[*promoted];
|
||||
self.sanitize_promoted(promoted_body, location);
|
||||
|
||||
let promoted_ty = promoted_body.return_ty();
|
||||
check_err(self, place, promoted_ty, sty);
|
||||
}
|
||||
}
|
||||
StaticKind::Static => {
|
||||
let ty = self.tcx().type_of(*def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
|
||||
check_err(self, place, ty, sty);
|
||||
let promoted_ty = promoted_body.return_ty();
|
||||
check_err(self, place, promoted_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
|
||||
if place.projection.is_none() {
|
||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||
let is_promoted = match place {
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
} => true,
|
||||
_ => false,
|
||||
check_err(self, place, ty, sty);
|
||||
}
|
||||
}
|
||||
PlaceTy::from_ty(sty)
|
||||
}
|
||||
};
|
||||
|
||||
if place.projection.is_empty() {
|
||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||
let is_promoted = match place {
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: box [],
|
||||
} => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !is_promoted {
|
||||
let tcx = self.tcx();
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().copy_trait().unwrap(),
|
||||
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
|
||||
};
|
||||
|
||||
if !is_promoted {
|
||||
let tcx = self.tcx();
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().copy_trait().unwrap(),
|
||||
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
|
||||
};
|
||||
|
||||
// In order to have a Copy operand, the type T of the
|
||||
// value must be Copy. Note that we prove that T: Copy,
|
||||
// rather than using the `is_copy_modulo_regions`
|
||||
// test. This is important because
|
||||
// `is_copy_modulo_regions` ignores the resulting region
|
||||
// obligations and assumes they pass. This can result in
|
||||
// bounds from Copy impls being unsoundly ignored (e.g.,
|
||||
// #29149). Note that we decide to use Copy before knowing
|
||||
// whether the bounds fully apply: in effect, the rule is
|
||||
// that if a value of some type could implement Copy, then
|
||||
// it must.
|
||||
self.cx.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::CopyBound,
|
||||
);
|
||||
}
|
||||
// To have a `Copy` operand, the type `T` of the
|
||||
// value must be `Copy`. Note that we prove that `T: Copy`,
|
||||
// rather than using the `is_copy_modulo_regions`
|
||||
// test. This is important because
|
||||
// `is_copy_modulo_regions` ignores the resulting region
|
||||
// obligations and assumes they pass. This can result in
|
||||
// bounds from `Copy` impls being unsoundly ignored (e.g.,
|
||||
// #29149). Note that we decide to use `Copy` before knowing
|
||||
// whether the bounds fully apply: in effect, the rule is
|
||||
// that if a value of some type could implement `Copy`, then
|
||||
// it must.
|
||||
self.cx.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::CopyBound,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for proj in place_projection {
|
||||
if place_ty.variant_index.is_none() {
|
||||
if place_ty.ty.references_error() {
|
||||
assert!(self.errors_reported);
|
||||
return PlaceTy::from_ty(self.tcx().types.err);
|
||||
}
|
||||
for elem in place.projection.iter() {
|
||||
if place_ty.variant_index.is_none() {
|
||||
if place_ty.ty.references_error() {
|
||||
assert!(self.errors_reported);
|
||||
return PlaceTy::from_ty(self.tcx().types.err);
|
||||
}
|
||||
place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
|
||||
}
|
||||
place_ty = self.sanitize_projection(place_ty, elem, place, location)
|
||||
}
|
||||
|
||||
place_ty
|
||||
})
|
||||
place_ty
|
||||
}
|
||||
|
||||
fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
|
||||
|
|
@ -1346,7 +1343,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
debug!("check_stmt: {:?}", stmt);
|
||||
let tcx = self.tcx();
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(ref place, ref rv) => {
|
||||
StatementKind::Assign(box(ref place, ref rv)) => {
|
||||
// Assignments to temporaries are not "interesting";
|
||||
// they are not caused by the user, but rather artifacts
|
||||
// of lowering. Assignments to other sorts of places *are* interesting
|
||||
|
|
@ -1354,7 +1351,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let category = match *place {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} => if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions {
|
||||
|
|
@ -1373,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
},
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
|
|
@ -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;
|
||||
if let Err(terr) = self.relate_type_and_user_type(
|
||||
place_ty,
|
||||
|
|
@ -1660,7 +1657,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let category = match *dest {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
|
|
@ -1682,7 +1679,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
|
|
@ -2416,19 +2413,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// *p`, where the `p` has type `&'b mut Foo`, for example, we
|
||||
// need to ensure that `'b: 'a`.
|
||||
|
||||
let mut borrowed_projection = &borrowed_place.projection;
|
||||
|
||||
debug!(
|
||||
"add_reborrow_constraint({:?}, {:?}, {:?})",
|
||||
location, borrow_region, borrowed_place
|
||||
);
|
||||
while let Some(box proj) = borrowed_projection {
|
||||
debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection);
|
||||
for (i, elem) in borrowed_place.projection.iter().enumerate().rev() {
|
||||
debug!("add_reborrow_constraint - iteration {:?}", elem);
|
||||
let proj_base = &borrowed_place.projection[..i];
|
||||
|
||||
match proj.elem {
|
||||
match elem {
|
||||
ProjectionElem::Deref => {
|
||||
let tcx = self.infcx.tcx;
|
||||
let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty;
|
||||
let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
|
||||
|
||||
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
|
||||
match base_ty.sty {
|
||||
|
|
@ -2490,10 +2486,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// other field access
|
||||
}
|
||||
}
|
||||
|
||||
// The "propagate" case. We need to check that our base is valid
|
||||
// for the borrow's lifetime.
|
||||
borrowed_projection = &proj.base;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,55 +25,54 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
|||
body: &Body<'tcx>,
|
||||
locals_state_at_exit: &LocalsStateAtExit,
|
||||
) -> bool {
|
||||
self.iterate(|place_base, place_projection| {
|
||||
let ignore = match place_base {
|
||||
// If a local variable is immutable, then we only need to track borrows to guard
|
||||
// against two kinds of errors:
|
||||
// * The variable being dropped while still borrowed (e.g., because the fn returns
|
||||
// a reference to a local variable)
|
||||
// * The variable being moved while still borrowed
|
||||
//
|
||||
// In particular, the variable cannot be mutated -- the "access checks" will fail --
|
||||
// so we don't have to worry about mutation while borrowed.
|
||||
PlaceBase::Local(index) => {
|
||||
match locals_state_at_exit {
|
||||
LocalsStateAtExit::AllAreInvalidated => false,
|
||||
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
|
||||
let ignore = !has_storage_dead_or_moved.contains(*index) &&
|
||||
body.local_decls[*index].mutability == Mutability::Not;
|
||||
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
|
||||
ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
_ => {}
|
||||
let ignore = match self.base {
|
||||
// If a local variable is immutable, then we only need to track borrows to guard
|
||||
// against two kinds of errors:
|
||||
// * The variable being dropped while still borrowed (e.g., because the fn returns
|
||||
// a reference to a local variable)
|
||||
// * The variable being moved while still borrowed
|
||||
//
|
||||
// In particular, the variable cannot be mutated -- the "access checks" will fail --
|
||||
// so we don't have to worry about mutation while borrowed.
|
||||
PlaceBase::Local(index) => {
|
||||
match locals_state_at_exit {
|
||||
LocalsStateAtExit::AllAreInvalidated => false,
|
||||
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
|
||||
let ignore = !has_storage_dead_or_moved.contains(index) &&
|
||||
body.local_decls[index].mutability == Mutability::Not;
|
||||
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
|
||||
ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
|
||||
false,
|
||||
PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
|
||||
tcx.is_mutable_static(def_id)
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ use crate::borrow_check::Overlap;
|
|||
use crate::borrow_check::{Deep, Shallow, AccessDepth};
|
||||
use rustc::hir;
|
||||
use rustc::mir::{
|
||||
Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
|
||||
StaticKind,
|
||||
Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
|
||||
};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use std::cmp::max;
|
||||
|
|
@ -67,39 +66,35 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
|
|||
// it's so common that it's a speed win to check for it first.
|
||||
if let Place {
|
||||
base: PlaceBase::Local(l1),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = borrow_place {
|
||||
if let PlaceRef {
|
||||
base: PlaceBase::Local(l2),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} = access_place {
|
||||
return l1 == l2;
|
||||
}
|
||||
}
|
||||
|
||||
borrow_place.iterate(|borrow_base, borrow_projections| {
|
||||
access_place.iterate(|access_base, access_projections| {
|
||||
place_components_conflict(
|
||||
tcx,
|
||||
param_env,
|
||||
body,
|
||||
(borrow_base, borrow_projections),
|
||||
borrow_kind,
|
||||
(access_base, access_projections),
|
||||
access,
|
||||
bias,
|
||||
)
|
||||
})
|
||||
})
|
||||
place_components_conflict(
|
||||
tcx,
|
||||
param_env,
|
||||
body,
|
||||
borrow_place,
|
||||
borrow_kind,
|
||||
access_place,
|
||||
access,
|
||||
bias,
|
||||
)
|
||||
}
|
||||
|
||||
fn place_components_conflict<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
|
||||
borrow_place: &Place<'tcx>,
|
||||
borrow_kind: BorrowKind,
|
||||
access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
|
||||
access_place: PlaceRef<'_, 'tcx>,
|
||||
access: AccessDepth,
|
||||
bias: PlaceConflictBias,
|
||||
) -> bool {
|
||||
|
|
@ -145,8 +140,8 @@ fn place_components_conflict<'tcx>(
|
|||
// and either equal or disjoint.
|
||||
// - If we did run out of access, the borrow can access a part of it.
|
||||
|
||||
let borrow_base = borrow_projections.0;
|
||||
let access_base = access_projections.0;
|
||||
let borrow_base = &borrow_place.base;
|
||||
let access_base = access_place.base;
|
||||
|
||||
match place_base_conflict(tcx, param_env, borrow_base, access_base) {
|
||||
Overlap::Arbitrary => {
|
||||
|
|
@ -163,147 +158,157 @@ fn place_components_conflict<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let mut borrow_projections = borrow_projections.1;
|
||||
let mut access_projections = access_projections.1;
|
||||
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
|
||||
for (i, (borrow_c, access_c)) in
|
||||
borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
|
||||
{
|
||||
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
||||
let borrow_proj_base = &borrow_place.projection[..i];
|
||||
|
||||
loop {
|
||||
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
|
||||
if let Some(borrow_c) = borrow_projections.next() {
|
||||
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
||||
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
||||
|
||||
if let Some(access_c) = access_projections.next() {
|
||||
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
||||
|
||||
// Borrow and access path both have more components.
|
||||
// Borrow and access path both have more components.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// - borrow of `a.(...)`, access to `a.(...)`
|
||||
// - borrow of `a.(...)`, access to `b.(...)`
|
||||
//
|
||||
// Here we only see the components we have checked so
|
||||
// far (in our examples, just the first component). We
|
||||
// check whether the components being borrowed vs
|
||||
// accessed are disjoint (as in the second example,
|
||||
// but not the first).
|
||||
match place_projection_conflict(
|
||||
tcx,
|
||||
body,
|
||||
borrow_base,
|
||||
borrow_proj_base,
|
||||
borrow_c,
|
||||
access_c,
|
||||
bias,
|
||||
) {
|
||||
Overlap::Arbitrary => {
|
||||
// We have encountered different fields of potentially
|
||||
// the same union - the borrow now partially overlaps.
|
||||
//
|
||||
// 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.(...)`
|
||||
// - borrow of `a.(...)`, access to `b.(...)`
|
||||
//
|
||||
// Here we only see the components we have checked so
|
||||
// far (in our examples, just the first component). We
|
||||
// check whether the components being borrowed vs
|
||||
// accessed are disjoint (as in the second example,
|
||||
// but not the first).
|
||||
match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) {
|
||||
Overlap::Arbitrary => {
|
||||
// We have encountered different fields of potentially
|
||||
// the same union - the borrow now partially overlaps.
|
||||
//
|
||||
// There is no *easy* way of comparing the fields
|
||||
// further on, because they might have different types
|
||||
// (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
|
||||
// `.y` come from different structs).
|
||||
//
|
||||
// We could try to do some things here - e.g., count
|
||||
// dereferences - but that's probably not a good
|
||||
// idea, at least for now, so just give up and
|
||||
// report a conflict. This is unsafe code anyway so
|
||||
// the user could always use raw pointers.
|
||||
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
||||
return true;
|
||||
}
|
||||
Overlap::EqualOrDisjoint => {
|
||||
// This is the recursive case - proceed to the next element.
|
||||
}
|
||||
Overlap::Disjoint => {
|
||||
// We have proven the borrow disjoint - further
|
||||
// projections will remain disjoint.
|
||||
debug!("borrow_conflicts_with_place: disjoint");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Borrow path is longer than the access path. Examples:
|
||||
//
|
||||
// - borrow 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");
|
||||
// We could try to do some things here - e.g., count
|
||||
// dereferences - but that's probably not a good
|
||||
// idea, at least for now, so just give up and
|
||||
// report a conflict. This is unsafe code anyway so
|
||||
// the user could always use raw pointers.
|
||||
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
||||
return true;
|
||||
}
|
||||
Overlap::EqualOrDisjoint => {
|
||||
// This is the recursive case - proceed to the next element.
|
||||
}
|
||||
Overlap::Disjoint => {
|
||||
// We have proven the borrow disjoint - further
|
||||
// projections will remain disjoint.
|
||||
debug!("borrow_conflicts_with_place: disjoint");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if borrow_place.projection.len() > access_place.projection.len() {
|
||||
for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
|
||||
{
|
||||
// Borrow path is longer than the access path. Examples:
|
||||
//
|
||||
// - borrow of `a.b.c`, access to `a.b`
|
||||
//
|
||||
// Here, we know that the borrow can access a part of
|
||||
// our place. This is a conflict if that is a part our
|
||||
// access cares about.
|
||||
|
||||
let 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
|
||||
|
|
@ -381,11 +386,12 @@ fn place_projection_conflict<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
pi1_base: &PlaceBase<'tcx>,
|
||||
pi1: &Projection<'tcx>,
|
||||
pi2: &Projection<'tcx>,
|
||||
pi1_proj_base: &[PlaceElem<'tcx>],
|
||||
pi1_elem: &PlaceElem<'tcx>,
|
||||
pi2_elem: &PlaceElem<'tcx>,
|
||||
bias: PlaceConflictBias,
|
||||
) -> Overlap {
|
||||
match (&pi1.elem, &pi2.elem) {
|
||||
match (pi1_elem, pi2_elem) {
|
||||
(ProjectionElem::Deref, ProjectionElem::Deref) => {
|
||||
// derefs (e.g., `*x` vs. `*x`) - recur.
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
|
||||
|
|
@ -397,7 +403,7 @@ fn place_projection_conflict<'tcx>(
|
|||
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty;
|
||||
let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
|
||||
match ty.sty {
|
||||
ty::Adt(def, _) if def.is_union() => {
|
||||
// Different fields of a union, we are basically stuck.
|
||||
|
|
@ -493,7 +499,7 @@ fn place_projection_conflict<'tcx>(
|
|||
// element (like -1 in Python) and `min_length` the first.
|
||||
// Therefore, `min_length - offset_from_end` gives the minimal possible
|
||||
// offset from the beginning
|
||||
if *offset_from_begin >= min_length - offset_from_end {
|
||||
if *offset_from_begin >= *min_length - *offset_from_end {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
|
|
@ -538,8 +544,8 @@ fn place_projection_conflict<'tcx>(
|
|||
| (ProjectionElem::Subslice { .. }, _)
|
||||
| (ProjectionElem::Downcast(..), _) => bug!(
|
||||
"mismatched projections in place_element_conflict: {:?} and {:?}",
|
||||
pi1,
|
||||
pi2
|
||||
pi1_elem,
|
||||
pi2_elem
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,17 +19,9 @@ pub trait IsPrefixOf<'cx, 'tcx> {
|
|||
|
||||
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
|
||||
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
|
||||
let mut cursor = other.projection;
|
||||
loop {
|
||||
if self.projection == cursor {
|
||||
return self.base == other.base;
|
||||
}
|
||||
|
||||
match cursor {
|
||||
None => return false,
|
||||
Some(proj) => cursor = &proj.base,
|
||||
}
|
||||
}
|
||||
self.base == other.base
|
||||
&& self.projection.len() <= other.projection.len()
|
||||
&& self.projection == &other.projection[..self.projection.len()]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,112 +73,113 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
// downcasts here, but may return a base of a downcast).
|
||||
|
||||
'cursor: loop {
|
||||
let proj = match &cursor {
|
||||
match &cursor {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: None,
|
||||
projection: [],
|
||||
}
|
||||
| // search yielded this leaf
|
||||
PlaceRef {
|
||||
base: PlaceBase::Static(_),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection: Some(proj),
|
||||
} => proj,
|
||||
};
|
||||
projection: [proj_base @ .., elem],
|
||||
} => {
|
||||
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 {
|
||||
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
|
||||
// FIXME: add union handling
|
||||
self.next = Some(PlaceRef {
|
||||
base: cursor.base,
|
||||
projection: &proj.base,
|
||||
});
|
||||
return Some(cursor);
|
||||
}
|
||||
ProjectionElem::Downcast(..) |
|
||||
ProjectionElem::Subslice { .. } |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
ProjectionElem::Index(_) => {
|
||||
cursor = PlaceRef {
|
||||
base: cursor.base,
|
||||
projection: &proj.base,
|
||||
};
|
||||
continue 'cursor;
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
// (handled below)
|
||||
}
|
||||
}
|
||||
assert_eq!(*elem, ProjectionElem::Deref);
|
||||
|
||||
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 {
|
||||
PrefixSet::Shallow => {
|
||||
// shallow prefixes are found by stripping away
|
||||
// fields, but stop at *any* dereference.
|
||||
// So we can just stop the traversal now.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::All => {
|
||||
// all prefixes: just blindly enqueue the base
|
||||
// of the projection.
|
||||
self.next = Some(PlaceRef {
|
||||
base: cursor.base,
|
||||
projection: &proj.base,
|
||||
});
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::Supporting => {
|
||||
// fall through!
|
||||
}
|
||||
}
|
||||
assert_eq!(self.kind, PrefixSet::Supporting);
|
||||
// Supporting prefixes: strip away fields and
|
||||
// derefs, except we stop at the deref of a shared
|
||||
// reference.
|
||||
|
||||
assert_eq!(self.kind, PrefixSet::Supporting);
|
||||
// supporting prefixes: strip away fields and
|
||||
// derefs, except we stop at the deref of a shared
|
||||
// reference.
|
||||
let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty;
|
||||
match ty.sty {
|
||||
ty::RawPtr(_) |
|
||||
ty::Ref(
|
||||
_, /*rgn*/
|
||||
_, /*ty*/
|
||||
hir::MutImmutable
|
||||
) => {
|
||||
// don't continue traversing over derefs of raw pointers or shared
|
||||
// borrows.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
|
||||
match ty.sty {
|
||||
ty::RawPtr(_) |
|
||||
ty::Ref(
|
||||
_, /*rgn*/
|
||||
_, /*ty*/
|
||||
hir::MutImmutable
|
||||
) => {
|
||||
// don't continue traversing over derefs of raw pointers or shared borrows.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
ty::Ref(
|
||||
_, /*rgn*/
|
||||
_, /*ty*/
|
||||
hir::MutMutable,
|
||||
) => {
|
||||
self.next = Some(PlaceRef {
|
||||
base: cursor.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
ty::Adt(..) if ty.is_box() => {
|
||||
self.next = Some(PlaceRef {
|
||||
base: cursor.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
_ => panic!("unknown type fed to Projection Deref."),
|
||||
}
|
||||
}
|
||||
|
||||
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."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
|||
_location: Location,
|
||||
) {
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(into, _) => {
|
||||
StatementKind::Assign(box(into, _)) => {
|
||||
if let PlaceBase::Local(local) = into.base {
|
||||
debug!(
|
||||
"visit_statement: statement={:?} local={:?} \
|
||||
|
|
@ -120,7 +120,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
|||
);
|
||||
if let Place {
|
||||
base: PlaceBase::Local(user_local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = path.place {
|
||||
self.mbcx.used_mut.insert(user_local);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl<'tcx> CFG<'tcx> {
|
|||
rvalue: Rvalue<'tcx>) {
|
||||
self.push(block, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(place.clone(), box rvalue)
|
||||
kind: StatementKind::Assign(box(place.clone(), rvalue))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
kind: StaticKind::Static,
|
||||
def_id: id,
|
||||
})),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}),
|
||||
|
||||
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
||||
|
|
@ -147,9 +147,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
place.clone(),
|
||||
box(
|
||||
place.clone(),
|
||||
UserTypeProjection { base: annotation_index, projs: vec![], }
|
||||
),
|
||||
Variance::Invariant,
|
||||
box UserTypeProjection { base: annotation_index, projs: vec![], },
|
||||
),
|
||||
},
|
||||
);
|
||||
|
|
@ -174,9 +176,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
Place::from(temp.clone()),
|
||||
box(
|
||||
Place::from(temp.clone()),
|
||||
UserTypeProjection { base: annotation_index, projs: vec![], },
|
||||
),
|
||||
Variance::Invariant,
|
||||
box UserTypeProjection { base: annotation_index, projs: vec![], },
|
||||
),
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -500,14 +500,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let mutability = match arg_place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} => this.local_decls[local].mutability,
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: Some(box Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
})
|
||||
projection: box [ProjectionElem::Deref],
|
||||
} => {
|
||||
debug_assert!(
|
||||
this.local_decls[local].is_ref_for_guard(),
|
||||
|
|
@ -517,24 +514,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
Place {
|
||||
ref base,
|
||||
projection: Some(box Projection {
|
||||
base: ref base_proj,
|
||||
elem: ProjectionElem::Field(upvar_index, _),
|
||||
}),
|
||||
projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
}
|
||||
| Place {
|
||||
ref base,
|
||||
projection: Some(box Projection {
|
||||
base: Some(box Projection {
|
||||
base: ref base_proj,
|
||||
elem: ProjectionElem::Field(upvar_index, _),
|
||||
}),
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
projection: box [
|
||||
ref proj_base @ ..,
|
||||
ProjectionElem::Field(upvar_index, _),
|
||||
ProjectionElem::Deref
|
||||
],
|
||||
} => {
|
||||
let place = PlaceRef {
|
||||
base,
|
||||
projection: base_proj,
|
||||
projection: proj_base,
|
||||
};
|
||||
|
||||
// Not projected from the implicit `self` in a closure.
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Create a "fake" temporary variable so that we check that the
|
||||
// value is Sized. Usually, this is caught in type checking, but
|
||||
// in the case of box expr there is no such check.
|
||||
if destination.projection.is_some() {
|
||||
if !destination.projection.is_empty() {
|
||||
this.local_decls
|
||||
.push(LocalDecl::new_temp(expr.ty, expr.span));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
source_info,
|
||||
kind: StatementKind::FakeRead(
|
||||
FakeReadCause::ForMatchedPlace,
|
||||
scrutinee_place.clone(),
|
||||
box(scrutinee_place.clone()),
|
||||
),
|
||||
});
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, place),
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)),
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -362,12 +362,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
block,
|
||||
Statement {
|
||||
source_info: pattern_source_info,
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()),
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())),
|
||||
},
|
||||
);
|
||||
|
||||
let ty_source_info = self.source_info(user_ty_span);
|
||||
let user_ty = box pat_ascription_ty.user_ty(
|
||||
let user_ty = pat_ascription_ty.user_ty(
|
||||
&mut self.canonical_user_type_annotations,
|
||||
place.ty(&self.local_decls, self.hir.tcx()).ty,
|
||||
ty_source_info.span,
|
||||
|
|
@ -377,7 +377,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Statement {
|
||||
source_info: ty_source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
place,
|
||||
box(
|
||||
place,
|
||||
user_ty,
|
||||
),
|
||||
// We always use invariant as the variance here. This is because the
|
||||
// variance field from the ascription refers to the variance to use
|
||||
// when applying the type to the value being matched, but this
|
||||
|
|
@ -393,7 +396,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// contrast, is intended to be used to relate `T` to the type of
|
||||
// `<expr>`.
|
||||
ty::Variance::Invariant,
|
||||
user_ty,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
|
@ -942,16 +944,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
for Binding { source, .. }
|
||||
in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
|
||||
{
|
||||
let mut cursor = &source.projection;
|
||||
while let Some(box Projection { base, elem }) = cursor {
|
||||
cursor = base;
|
||||
if let ProjectionElem::Deref = elem {
|
||||
fake_borrows.insert(Place {
|
||||
base: source.base.clone(),
|
||||
projection: cursor.clone(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
if let Some(i) =
|
||||
source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
|
||||
{
|
||||
let proj_base = &source.projection[..i];
|
||||
|
||||
fake_borrows.insert(Place {
|
||||
base: source.base.clone(),
|
||||
projection: proj_base.to_vec().into_boxed_slice(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1295,18 +1296,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
||||
for place in fake_borrows
|
||||
{
|
||||
let mut prefix_cursor = &place.projection;
|
||||
while let Some(box Projection { base, elem }) = prefix_cursor {
|
||||
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||
let proj_base = &place.projection[..i];
|
||||
|
||||
if let ProjectionElem::Deref = elem {
|
||||
// Insert a shallow borrow after a deref. For other
|
||||
// projections the borrow of prefix_cursor will
|
||||
// conflict with any mutation of base.
|
||||
all_fake_borrows.push(PlaceRef {
|
||||
base: &place.base,
|
||||
projection: base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
prefix_cursor = base;
|
||||
}
|
||||
|
||||
all_fake_borrows.push(place.as_ref());
|
||||
|
|
@ -1489,7 +1490,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
BorrowKind::Shallow,
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: place.projection.clone(),
|
||||
projection: place.projection.to_vec().into_boxed_slice(),
|
||||
},
|
||||
);
|
||||
self.cfg.push_assign(
|
||||
|
|
@ -1520,7 +1521,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
source_info: guard_end,
|
||||
kind: StatementKind::FakeRead(
|
||||
FakeReadCause::ForMatchGuard,
|
||||
Place::from(temp),
|
||||
box(Place::from(temp)),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
|
@ -1570,7 +1571,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
post_guard_block,
|
||||
Statement {
|
||||
source_info: guard_end,
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
|
||||
kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -1603,7 +1604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ascription.user_ty,
|
||||
);
|
||||
|
||||
let user_ty = box ascription.user_ty.clone().user_ty(
|
||||
let user_ty = ascription.user_ty.clone().user_ty(
|
||||
&mut self.canonical_user_type_annotations,
|
||||
ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
|
||||
source_info.span
|
||||
|
|
@ -1613,9 +1614,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
ascription.source.clone(),
|
||||
box(
|
||||
ascription.source.clone(),
|
||||
user_ty,
|
||||
),
|
||||
ascription.variance,
|
||||
user_ty,
|
||||
),
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -609,7 +609,7 @@ where
|
|||
unpack!(block = builder.in_breakable_scope(
|
||||
None,
|
||||
START_BLOCK,
|
||||
Place::RETURN_PLACE,
|
||||
Place::return_place(),
|
||||
|builder| {
|
||||
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||
builder.args_and_body(block, &arguments, arg_scope, &body.value)
|
||||
|
|
@ -670,7 +670,7 @@ fn construct_const<'a, 'tcx>(
|
|||
let mut block = START_BLOCK;
|
||||
let ast_expr = &tcx.hir().body(body_id).value;
|
||||
let expr = builder.hir.mirror(ast_expr);
|
||||
unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr));
|
||||
unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
|
||||
|
||||
let source_info = builder.source_info(span);
|
||||
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
||||
|
|
@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let body = self.hir.mirror(ast_body);
|
||||
self.into(&Place::RETURN_PLACE, block, body)
|
||||
self.into(&Place::return_place(), block, body)
|
||||
}
|
||||
|
||||
fn set_correct_source_scope_for_arg(
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ impl<'tcx> Scopes<'tcx> {
|
|||
match target {
|
||||
BreakableTarget::Return => {
|
||||
let scope = &self.breakable_scopes[0];
|
||||
if scope.break_destination != Place::RETURN_PLACE {
|
||||
if scope.break_destination != Place::return_place() {
|
||||
span_bug!(span, "`return` in item with no return scope");
|
||||
}
|
||||
(scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
|
||||
|
|
@ -853,11 +853,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
_ if self.local_scope().is_none() => (),
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(cond_temp),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(cond_temp),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) => {
|
||||
// Manually drop the condition on both branches.
|
||||
let top_scope = self.scopes.scopes.last_mut().unwrap();
|
||||
|
|
|
|||
|
|
@ -10,19 +10,17 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
|
|||
path: MovePathIndex,
|
||||
mut cond: F)
|
||||
-> Option<MovePathIndex>
|
||||
where F: FnMut(&mir::Projection<'tcx>) -> bool
|
||||
where F: FnMut(&mir::PlaceElem<'tcx>) -> bool
|
||||
{
|
||||
let mut next_child = move_data.move_paths[path].first_child;
|
||||
while let Some(child_index) = next_child {
|
||||
match move_data.move_paths[child_index].place.projection {
|
||||
Some(ref proj) => {
|
||||
if cond(proj) {
|
||||
return Some(child_index)
|
||||
}
|
||||
let move_path_children = &move_data.move_paths[child_index];
|
||||
if let Some(elem) = move_path_children.place.projection.last() {
|
||||
if cond(elem) {
|
||||
return Some(child_index)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
next_child = move_data.move_paths[child_index].next_sibling;
|
||||
next_child = move_path_children.next_sibling;
|
||||
}
|
||||
|
||||
None
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
// If the borrowed place is a local with no projections, all other borrows of this
|
||||
// local must conflict. This is purely an optimization so we don't have to call
|
||||
// `places_conflict` for every borrow.
|
||||
if place.projection.is_none() {
|
||||
if place.projection.is_empty() {
|
||||
trans.kill_all(other_borrows_of_local);
|
||||
return;
|
||||
}
|
||||
|
|
@ -268,8 +268,8 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
|
|||
|
||||
debug!("Borrows::statement_effect: stmt={:?}", stmt);
|
||||
match stmt.kind {
|
||||
mir::StatementKind::Assign(ref lhs, ref rhs) => {
|
||||
if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
|
||||
mir::StatementKind::Assign(box(ref lhs, ref rhs)) => {
|
||||
if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
|
||||
if place.ignore_borrow(
|
||||
self.tcx,
|
||||
self.body,
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
match stmt.kind {
|
||||
StatementKind::StorageLive(l) => sets.gen(l),
|
||||
StatementKind::StorageDead(l) => sets.kill(l),
|
||||
StatementKind::Assign(ref place, _)
|
||||
| StatementKind::SetDiscriminant { ref place, .. } => {
|
||||
StatementKind::Assign(box(ref place, _))
|
||||
| StatementKind::SetDiscriminant { box ref place, .. } => {
|
||||
if let PlaceBase::Local(local) = place.base {
|
||||
sets.gen(local);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,72 +94,74 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
||||
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
||||
debug!("lookup({:?})", place);
|
||||
place.iterate(|place_base, place_projection| {
|
||||
let mut base = match place_base {
|
||||
PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local],
|
||||
PlaceBase::Static(..) => {
|
||||
return Err(MoveError::cannot_move_out_of(self.loc, Static));
|
||||
let mut base = match place.base {
|
||||
PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
|
||||
PlaceBase::Static(..) => {
|
||||
return Err(MoveError::cannot_move_out_of(self.loc, Static));
|
||||
}
|
||||
};
|
||||
|
||||
for (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 body = self.builder.body;
|
||||
let tcx = self.builder.tcx;
|
||||
let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
|
||||
match place_ty.sty {
|
||||
ty::Ref(..) | ty::RawPtr(..) => {
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
self.loc,
|
||||
BorrowedContent {
|
||||
target_place: Place {
|
||||
base: place_base.clone(),
|
||||
projection: Some(Box::new(proj.clone())),
|
||||
},
|
||||
},
|
||||
));
|
||||
}
|
||||
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()))
|
||||
let proj = &place.projection[..i+1];
|
||||
base = match self
|
||||
.builder
|
||||
.data
|
||||
.rev_lookup
|
||||
.projections
|
||||
.entry((base, elem.lift()))
|
||||
{
|
||||
Entry::Occupied(ent) => *ent.get(),
|
||||
Entry::Vacant(ent) => {
|
||||
|
|
@ -169,18 +171,17 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
&mut self.builder.data.init_path_map,
|
||||
Some(base),
|
||||
Place {
|
||||
base: place_base.clone(),
|
||||
projection: Some(Box::new(proj.clone())),
|
||||
base: place.base.clone(),
|
||||
projection: proj.to_vec().into_boxed_slice(),
|
||||
},
|
||||
);
|
||||
ent.insert(path);
|
||||
path
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(base)
|
||||
})
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
fn create_move_path(&mut self, place: &Place<'tcx>) {
|
||||
|
|
@ -267,7 +268,7 @@ struct Gatherer<'b, 'a, 'tcx> {
|
|||
impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(ref place, ref rval) => {
|
||||
StatementKind::Assign(box(ref place, ref rval)) => {
|
||||
self.create_move_path(place);
|
||||
if let RvalueInitializationState::Shallow = rval.initialization_state() {
|
||||
// Box starts out uninitialized - need to create a separate
|
||||
|
|
@ -355,7 +356,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
| TerminatorKind::Unreachable => {}
|
||||
|
||||
TerminatorKind::Return => {
|
||||
self.gather_move(&Place::RETURN_PLACE);
|
||||
self.gather_move(&Place::return_place());
|
||||
}
|
||||
|
||||
TerminatorKind::Assert { ref cond, .. } => {
|
||||
|
|
@ -435,9 +436,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
|
||||
// Check if we are assigning into a field of a union, if so, lookup the place
|
||||
// of the union so it is marked as initialized again.
|
||||
if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) =
|
||||
place.projection
|
||||
{
|
||||
if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
|
||||
if let ty::Adt(def, _) =
|
||||
Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
|
||||
{
|
||||
|
|
|
|||
|
|
@ -245,23 +245,21 @@ impl MovePathLookup {
|
|||
// alternative will *not* create a MovePath on the fly for an
|
||||
// unknown place, but will rather return the nearest available
|
||||
// parent.
|
||||
pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult {
|
||||
place_ref.iterate(|place_base, place_projection| {
|
||||
let mut result = match place_base {
|
||||
PlaceBase::Local(local) => self.locals[*local],
|
||||
PlaceBase::Static(..) => return LookupResult::Parent(None),
|
||||
};
|
||||
pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
|
||||
let mut result = match place.base {
|
||||
PlaceBase::Local(local) => self.locals[*local],
|
||||
PlaceBase::Static(..) => return LookupResult::Parent(None),
|
||||
};
|
||||
|
||||
for proj in place_projection {
|
||||
if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
|
||||
result = subpath;
|
||||
} else {
|
||||
return LookupResult::Parent(Some(result));
|
||||
}
|
||||
for elem in place.projection.iter() {
|
||||
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
|
||||
result = subpath;
|
||||
} else {
|
||||
return LookupResult::Parent(Some(result));
|
||||
}
|
||||
}
|
||||
|
||||
LookupResult::Exact(result)
|
||||
})
|
||||
LookupResult::Exact(result)
|
||||
}
|
||||
|
||||
pub fn find_local(&self, local: Local) -> MovePathIndex {
|
||||
|
|
@ -329,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
|
|||
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
|
||||
loop {
|
||||
let path = &self.move_paths[mpi];
|
||||
if let Place { base: PlaceBase::Local(l), projection: None } = path.place {
|
||||
if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
|
||||
return Some(l);
|
||||
}
|
||||
if let Some(parent) = path.parent {
|
||||
|
|
|
|||
|
|
@ -472,39 +472,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// avoid allocations.
|
||||
pub(super) fn eval_place_to_op(
|
||||
&self,
|
||||
mir_place: &mir::Place<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
layout: Option<TyLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
use rustc::mir::PlaceBase;
|
||||
|
||||
mir_place.iterate(|place_base, place_projection| {
|
||||
let mut op = match place_base {
|
||||
PlaceBase::Local(mir::RETURN_PLACE) =>
|
||||
throw_unsup!(ReadFromReturnPointer),
|
||||
PlaceBase::Local(local) => {
|
||||
// Do not use the layout passed in as argument if the base we are looking at
|
||||
// here is not the entire place.
|
||||
// FIXME use place_projection.is_empty() when is available
|
||||
let layout = if mir_place.projection.is_none() {
|
||||
layout
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut op = match &place.base {
|
||||
PlaceBase::Local(mir::RETURN_PLACE) =>
|
||||
throw_unsup!(ReadFromReturnPointer),
|
||||
PlaceBase::Local(local) => {
|
||||
// Do not use the layout passed in as argument if the base we are looking at
|
||||
// here is not the entire place.
|
||||
// FIXME use place_projection.is_empty() when is available
|
||||
let layout = if place.projection.is_empty() {
|
||||
layout
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
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)?
|
||||
self.access_local(self.frame(), *local, layout)?
|
||||
}
|
||||
PlaceBase::Static(place_static) => {
|
||||
self.eval_static_to_mplace(&place_static)?.into()
|
||||
}
|
||||
};
|
||||
|
||||
trace!("eval_place_to_op: got {:?}", *op);
|
||||
Ok(op)
|
||||
})
|
||||
for elem in place.projection.iter() {
|
||||
op = self.operand_projection(op, elem)?
|
||||
}
|
||||
|
||||
trace!("eval_place_to_op: got {:?}", *op);
|
||||
Ok(op)
|
||||
}
|
||||
|
||||
/// Evaluate the operand, returning a place where you can then find the data.
|
||||
|
|
|
|||
|
|
@ -629,45 +629,43 @@ where
|
|||
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
|
||||
pub fn eval_place(
|
||||
&mut self,
|
||||
mir_place: &mir::Place<'tcx>,
|
||||
place: &mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
||||
use rustc::mir::PlaceBase;
|
||||
|
||||
mir_place.iterate(|place_base, place_projection| {
|
||||
let mut place = match place_base {
|
||||
PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
|
||||
Some(return_place) => {
|
||||
// We use our layout to verify our assumption; caller will validate
|
||||
// their layout on return.
|
||||
PlaceTy {
|
||||
place: *return_place,
|
||||
layout: self.layout_of(
|
||||
self.subst_from_frame_and_normalize_erasing_regions(
|
||||
self.frame().body.return_ty()
|
||||
)
|
||||
)?,
|
||||
}
|
||||
let mut place_ty = match &place.base {
|
||||
PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
|
||||
Some(return_place) => {
|
||||
// We use our layout to verify our assumption; caller will validate
|
||||
// their layout on return.
|
||||
PlaceTy {
|
||||
place: *return_place,
|
||||
layout: self.layout_of(
|
||||
self.subst_from_frame_and_normalize_erasing_regions(
|
||||
self.frame().body.return_ty()
|
||||
)
|
||||
)?,
|
||||
}
|
||||
None => throw_unsup!(InvalidNullPointerUsage),
|
||||
}
|
||||
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 {
|
||||
// This works even for dead/uninitialized locals; we check further when writing
|
||||
place: Place::Local {
|
||||
frame: self.cur_frame(),
|
||||
local: *local,
|
||||
},
|
||||
layout: self.layout_of_local(self.frame(), *local, None)?,
|
||||
},
|
||||
PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(),
|
||||
};
|
||||
layout: self.layout_of_local(self.frame(), *local, None)?,
|
||||
},
|
||||
PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
|
||||
};
|
||||
|
||||
for proj in place_projection {
|
||||
place = self.place_projection(place, &proj.elem)?
|
||||
}
|
||||
for elem in place.projection.iter() {
|
||||
place_ty = self.place_projection(place_ty, elem)?
|
||||
}
|
||||
|
||||
self.dump_place(place.place);
|
||||
Ok(place)
|
||||
})
|
||||
self.dump_place(place_ty.place);
|
||||
Ok(place_ty)
|
||||
}
|
||||
|
||||
/// Write a scalar to a place
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.memory.tcx.span = stmt.source_info.span;
|
||||
|
||||
match stmt.kind {
|
||||
Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
|
||||
Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,
|
||||
|
||||
SetDiscriminant {
|
||||
ref place,
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Don't forget to check the return type!
|
||||
if let Some(caller_ret) = dest {
|
||||
let callee_ret = self.eval_place(
|
||||
&mir::Place::RETURN_PLACE
|
||||
&mir::Place::return_place()
|
||||
)?;
|
||||
if !Self::check_argument_compat(
|
||||
rust_abi,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()),
|
||||
kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())),
|
||||
});
|
||||
}
|
||||
let patch = {
|
||||
|
|
@ -308,7 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
|
|||
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
|
||||
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
|
||||
|
||||
let dest = Place::RETURN_PLACE;
|
||||
let dest = Place::return_place();
|
||||
let src = Place::from(Local::new(1+0)).deref();
|
||||
|
||||
match self_ty.sty {
|
||||
|
|
@ -415,8 +415,10 @@ impl CloneShimBuilder<'tcx> {
|
|||
let rcvr = Place::from(Local::new(1+0)).deref();
|
||||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::RETURN_PLACE,
|
||||
box Rvalue::Use(Operand::Copy(rcvr))
|
||||
box(
|
||||
Place::return_place(),
|
||||
Rvalue::Use(Operand::Copy(rcvr))
|
||||
)
|
||||
)
|
||||
);
|
||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||
|
|
@ -458,8 +460,10 @@ impl CloneShimBuilder<'tcx> {
|
|||
// `let ref_loc: &ty = &src;`
|
||||
let statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
ref_loc.clone(),
|
||||
box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
|
||||
box(
|
||||
ref_loc.clone(),
|
||||
Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -486,8 +490,10 @@ impl CloneShimBuilder<'tcx> {
|
|||
let cond = self.make_place(Mutability::Mut, tcx.types.bool);
|
||||
let compute_cond = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
cond.clone(),
|
||||
box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||
box(
|
||||
cond.clone(),
|
||||
Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
@ -521,14 +527,18 @@ impl CloneShimBuilder<'tcx> {
|
|||
let inits = vec![
|
||||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::from(beg),
|
||||
box Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
box(
|
||||
Place::from(beg),
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
)
|
||||
)
|
||||
),
|
||||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
end.clone(),
|
||||
box Rvalue::Use(Operand::Constant(self.make_usize(len)))
|
||||
box(
|
||||
end.clone(),
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(len)))
|
||||
)
|
||||
)
|
||||
)
|
||||
];
|
||||
|
|
@ -559,11 +569,13 @@ impl CloneShimBuilder<'tcx> {
|
|||
let statements = vec![
|
||||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::from(beg),
|
||||
box Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Copy(Place::from(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
box(
|
||||
Place::from(beg),
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Copy(Place::from(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -582,8 +594,10 @@ impl CloneShimBuilder<'tcx> {
|
|||
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
|
||||
let init = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::from(beg),
|
||||
box Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
box(
|
||||
Place::from(beg),
|
||||
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||
)
|
||||
)
|
||||
);
|
||||
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
|
||||
|
|
@ -609,11 +623,13 @@ impl CloneShimBuilder<'tcx> {
|
|||
// `goto #6;`
|
||||
let statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Place::from(beg),
|
||||
box Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Copy(Place::from(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
box(
|
||||
Place::from(beg),
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Copy(Place::from(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
@ -727,8 +743,10 @@ fn build_call_shim<'tcx>(
|
|||
statements.push(Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::from(ref_rcvr),
|
||||
box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
|
||||
box(
|
||||
Place::from(ref_rcvr),
|
||||
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
|
||||
)
|
||||
)
|
||||
});
|
||||
Operand::Move(Place::from(ref_rcvr))
|
||||
|
|
@ -773,7 +791,7 @@ fn build_call_shim<'tcx>(
|
|||
block(&mut blocks, statements, TerminatorKind::Call {
|
||||
func: callee,
|
||||
args,
|
||||
destination: Some((Place::RETURN_PLACE,
|
||||
destination: Some((Place::return_place(),
|
||||
BasicBlock::new(1))),
|
||||
cleanup: if let Adjustment::RefMut = rcvr_adjustment {
|
||||
Some(BasicBlock::new(3))
|
||||
|
|
@ -868,7 +886,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
|
|||
debug!("build_ctor: variant_index={:?}", variant_index);
|
||||
|
||||
let statements = expand_aggregate(
|
||||
Place::RETURN_PLACE,
|
||||
Place::return_place(),
|
||||
adt_def
|
||||
.variants[variant_index]
|
||||
.fields
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@ pub struct AddRetag;
|
|||
fn is_stable(
|
||||
place: PlaceRef<'_, '_>,
|
||||
) -> bool {
|
||||
if let Some(proj) = &place.projection {
|
||||
match proj.elem {
|
||||
place.projection.iter().all(|elem| {
|
||||
match elem {
|
||||
// Which place this evaluates to can change with any memory write,
|
||||
// so cannot assume this to be stable.
|
||||
ProjectionElem::Deref =>
|
||||
false,
|
||||
ProjectionElem::Deref => false,
|
||||
// Array indices are intersting, but MIR building generates a *fresh*
|
||||
// temporary for every array access, so the index cannot be changed as
|
||||
// a side-effect.
|
||||
|
|
@ -31,15 +30,9 @@ fn is_stable(
|
|||
ProjectionElem::Field { .. } |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
ProjectionElem::Subslice { .. } |
|
||||
ProjectionElem::Downcast { .. } =>
|
||||
is_stable(PlaceRef {
|
||||
base: place.base,
|
||||
projection: &proj.base,
|
||||
}),
|
||||
ProjectionElem::Downcast { .. } => true,
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Determine whether this type may be a reference (or box), and thus needs retagging.
|
||||
|
|
@ -96,7 +89,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
basic_blocks[START_BLOCK].statements.splice(0..0,
|
||||
places.into_iter().map(|place| Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::FnEntry, place),
|
||||
kind: StatementKind::Retag(RetagKind::FnEntry, box(place)),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
@ -132,7 +125,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
for (source_info, dest_place, dest_block) in returns {
|
||||
basic_blocks[dest_block].statements.insert(0, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::Default, dest_place),
|
||||
kind: StatementKind::Retag(RetagKind::Default, box(dest_place)),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -144,11 +137,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
for i in (0..block_data.statements.len()).rev() {
|
||||
let (retag_kind, place) = match block_data.statements[i].kind {
|
||||
// If we are casting *from* a reference, we may have to retag-as-raw.
|
||||
StatementKind::Assign(ref place, box Rvalue::Cast(
|
||||
StatementKind::Assign(box(ref place, Rvalue::Cast(
|
||||
CastKind::Misc,
|
||||
ref src,
|
||||
dest_ty,
|
||||
)) => {
|
||||
))) => {
|
||||
let src_ty = src.ty(&*local_decls, tcx);
|
||||
if src_ty.is_region_ptr() {
|
||||
// The only `Misc` casts on references are those creating raw pointers.
|
||||
|
|
@ -162,7 +155,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
// Assignments of reference or ptr type are the ones where we may have
|
||||
// to update tags. This includes `x = &[mut] ...` and hence
|
||||
// we also retag after taking a reference!
|
||||
StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => {
|
||||
StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => {
|
||||
let kind = match rvalue {
|
||||
Rvalue::Ref(_, borrow_kind, _)
|
||||
if borrow_kind.allows_two_phase_borrow()
|
||||
|
|
@ -180,7 +173,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
let source_info = block_data.statements[i].source_info;
|
||||
block_data.statements.insert(i+1, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(retag_kind, place),
|
||||
kind: StatementKind::Retag(retag_kind, box(place)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,127 +200,127 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
context: PlaceContext,
|
||||
_location: Location) {
|
||||
place.iterate(|place_base, place_projections| {
|
||||
match place_base {
|
||||
PlaceBase::Local(..) => {
|
||||
// Locals are safe.
|
||||
}
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
|
||||
bug!("unsafety checking should happen before promotion")
|
||||
}
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
|
||||
if self.tcx.is_mutable_static(*def_id) {
|
||||
self.require_unsafe("use of mutable static",
|
||||
"mutable statics can be mutated by multiple threads: aliasing \
|
||||
violations or data races will cause undefined behavior",
|
||||
UnsafetyViolationKind::General);
|
||||
} else if self.tcx.is_foreign_item(*def_id) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
self.source_scope_local_data[source_info.scope].lint_root;
|
||||
self.register_violations(&[UnsafetyViolation {
|
||||
source_info,
|
||||
description: InternedString::intern("use of extern static"),
|
||||
details: InternedString::intern(
|
||||
"extern statics are not controlled by the Rust type system: \
|
||||
invalid data, aliasing violations or data races will cause \
|
||||
undefined behavior"),
|
||||
kind: UnsafetyViolationKind::ExternStatic(lint_root)
|
||||
}], &[]);
|
||||
}
|
||||
match place.base {
|
||||
PlaceBase::Local(..) => {
|
||||
// Locals are safe.
|
||||
}
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
|
||||
bug!("unsafety checking should happen before promotion")
|
||||
}
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
|
||||
if self.tcx.is_mutable_static(def_id) {
|
||||
self.require_unsafe("use of mutable static",
|
||||
"mutable statics can be mutated by multiple threads: aliasing \
|
||||
violations or data races will cause undefined behavior",
|
||||
UnsafetyViolationKind::General);
|
||||
} else if self.tcx.is_foreign_item(def_id) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
self.source_scope_local_data[source_info.scope].lint_root;
|
||||
self.register_violations(&[UnsafetyViolation {
|
||||
source_info,
|
||||
description: InternedString::intern("use of extern static"),
|
||||
details: InternedString::intern(
|
||||
"extern statics are not controlled by the Rust type system: \
|
||||
invalid data, aliasing violations or data races will cause \
|
||||
undefined behavior"),
|
||||
kind: UnsafetyViolationKind::ExternStatic(lint_root)
|
||||
}], &[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for proj in place_projections {
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
self.source_scope_local_data[source_info.scope].lint_root;
|
||||
self.register_violations(&[UnsafetyViolation {
|
||||
source_info,
|
||||
description: InternedString::intern("borrow of packed field"),
|
||||
details: InternedString::intern(
|
||||
"fields of packed structs might be misaligned: dereferencing a \
|
||||
misaligned pointer or even just creating a misaligned reference \
|
||||
is undefined behavior"),
|
||||
kind: UnsafetyViolationKind::BorrowPacked(lint_root)
|
||||
}], &[]);
|
||||
}
|
||||
for (i, elem) in place.projection.iter().enumerate() {
|
||||
let proj_base = &place.projection[..i];
|
||||
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
self.source_scope_local_data[source_info.scope].lint_root;
|
||||
self.register_violations(&[UnsafetyViolation {
|
||||
source_info,
|
||||
description: InternedString::intern("borrow of packed field"),
|
||||
details: InternedString::intern(
|
||||
"fields of packed structs might be misaligned: dereferencing a \
|
||||
misaligned pointer or even just creating a misaligned reference \
|
||||
is undefined behavior"),
|
||||
kind: UnsafetyViolationKind::BorrowPacked(lint_root)
|
||||
}], &[]);
|
||||
}
|
||||
let is_borrow_of_interior_mut = context.is_borrow() &&
|
||||
!Place::ty_from(&place.base, &proj.base, self.body, self.tcx)
|
||||
.ty
|
||||
.is_freeze(self.tcx, self.param_env, self.source_info.span);
|
||||
// prevent
|
||||
// * `&mut x.field`
|
||||
// * `x.field = y;`
|
||||
// * `&x.field` if `field`'s type has interior mutability
|
||||
// because either of these would allow modifying the layout constrained field and
|
||||
// insert values that violate the layout constraints.
|
||||
if context.is_mutating_use() || is_borrow_of_interior_mut {
|
||||
self.check_mut_borrowing_layout_constrained_field(
|
||||
place, context.is_mutating_use(),
|
||||
);
|
||||
}
|
||||
let is_borrow_of_interior_mut = context.is_borrow() &&
|
||||
!Place::ty_from(&place.base, proj_base, self.body, self.tcx)
|
||||
.ty
|
||||
.is_freeze(self.tcx, self.param_env, self.source_info.span);
|
||||
// prevent
|
||||
// * `&mut x.field`
|
||||
// * `x.field = y;`
|
||||
// * `&x.field` if `field`'s type has interior mutability
|
||||
// because either of these would allow modifying the layout constrained field and
|
||||
// insert values that violate the layout constraints.
|
||||
if context.is_mutating_use() || is_borrow_of_interior_mut {
|
||||
self.check_mut_borrowing_layout_constrained_field(
|
||||
place, context.is_mutating_use(),
|
||||
);
|
||||
}
|
||||
let old_source_info = self.source_info;
|
||||
if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
|
||||
if self.body.local_decls[*local].internal {
|
||||
// Internal locals are used in the `move_val_init` desugaring.
|
||||
// We want to check unsafety against the source info of the
|
||||
// desugaring, rather than the source info of the RHS.
|
||||
self.source_info = self.body.local_decls[*local].source_info;
|
||||
}
|
||||
let old_source_info = self.source_info;
|
||||
if let (PlaceBase::Local(local), None) = (&place.base, &proj.base) {
|
||||
if self.body.local_decls[*local].internal {
|
||||
// Internal locals are used in the `move_val_init` desugaring.
|
||||
// We want to check unsafety against the source info of the
|
||||
// desugaring, rather than the source info of the RHS.
|
||||
self.source_info = self.body.local_decls[*local].source_info;
|
||||
}
|
||||
}
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||
match base_ty.sty {
|
||||
ty::RawPtr(..) => {
|
||||
self.require_unsafe("dereference of raw pointer",
|
||||
"raw pointers may be NULL, dangling or unaligned; they can violate \
|
||||
aliasing rules and cause data races: all of these are undefined \
|
||||
behavior", UnsafetyViolationKind::General)
|
||||
}
|
||||
let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
|
||||
match base_ty.sty {
|
||||
ty::RawPtr(..) => {
|
||||
self.require_unsafe("dereference of raw pointer",
|
||||
"raw pointers may be NULL, dangling or unaligned; they can violate \
|
||||
aliasing rules and cause data races: all of these are undefined \
|
||||
behavior", UnsafetyViolationKind::General)
|
||||
}
|
||||
ty::Adt(adt, _) => {
|
||||
if adt.is_union() {
|
||||
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
|
||||
context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
|
||||
context == PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AsmOutput
|
||||
)
|
||||
{
|
||||
let elem_ty = match proj.elem {
|
||||
ProjectionElem::Field(_, ty) => ty,
|
||||
_ => span_bug!(
|
||||
self.source_info.span,
|
||||
"non-field projection {:?} from union?",
|
||||
place)
|
||||
};
|
||||
if !elem_ty.is_copy_modulo_regions(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
ty::Adt(adt, _) => {
|
||||
if adt.is_union() {
|
||||
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
|
||||
context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
|
||||
context == PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AsmOutput
|
||||
)
|
||||
{
|
||||
let elem_ty = match elem {
|
||||
ProjectionElem::Field(_, ty) => ty,
|
||||
_ => span_bug!(
|
||||
self.source_info.span,
|
||||
) {
|
||||
self.require_unsafe(
|
||||
"assignment to non-`Copy` union field",
|
||||
"the previous content of the field will be dropped, which \
|
||||
causes undefined behavior if the field was not properly \
|
||||
initialized", UnsafetyViolationKind::General)
|
||||
} else {
|
||||
// write to non-move union, safe
|
||||
}
|
||||
"non-field projection {:?} from union?",
|
||||
place)
|
||||
};
|
||||
if !elem_ty.is_copy_modulo_regions(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
self.source_info.span,
|
||||
) {
|
||||
self.require_unsafe(
|
||||
"assignment to non-`Copy` union field",
|
||||
"the previous content of the field will be dropped, which \
|
||||
causes undefined behavior if the field was not properly \
|
||||
initialized", UnsafetyViolationKind::General)
|
||||
} else {
|
||||
self.require_unsafe("access to union field",
|
||||
"the field may not be properly initialized: using \
|
||||
uninitialized data will cause undefined behavior",
|
||||
UnsafetyViolationKind::General)
|
||||
// write to non-move union, safe
|
||||
}
|
||||
} else {
|
||||
self.require_unsafe("access to union field",
|
||||
"the field may not be properly initialized: using \
|
||||
uninitialized data will cause undefined behavior",
|
||||
UnsafetyViolationKind::General)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.source_info = old_source_info;
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
self.source_info = old_source_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -407,12 +407,13 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
is_mut_use: bool,
|
||||
) {
|
||||
let mut projection = &place.projection;
|
||||
while let Some(proj) = projection {
|
||||
match proj.elem {
|
||||
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||
let proj_base = &place.projection[..i];
|
||||
|
||||
match elem {
|
||||
ProjectionElem::Field(..) => {
|
||||
let ty =
|
||||
Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx)
|
||||
Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx)
|
||||
.ty;
|
||||
match ty.sty {
|
||||
ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
|
||||
|
|
@ -447,7 +448,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
projection = &proj.base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements {
|
|||
location: Location) {
|
||||
match statement.kind {
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _))
|
||||
| StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
|
||||
| StatementKind::FakeRead(..) => statement.make_nop(),
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,53 +282,53 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
|
||||
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
||||
trace!("eval_place(place={:?})", place);
|
||||
place.iterate(|place_base, place_projection| {
|
||||
let mut eval = match place_base {
|
||||
PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
|
||||
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id());
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
|
||||
let instance = Instance::new(self.source.def_id(), substs);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: Some(*promoted),
|
||||
};
|
||||
let res = self.use_ecx(source_info, |this| {
|
||||
this.ecx.const_eval_raw(cid)
|
||||
})?;
|
||||
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 mut eval = match place.base {
|
||||
PlaceBase::Local(loc) => self.get_const(loc).clone()?,
|
||||
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id());
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
|
||||
let instance = Instance::new(self.source.def_id(), substs);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted),
|
||||
};
|
||||
let res = self.use_ecx(source_info, |this| {
|
||||
this.ecx.const_eval_raw(cid)
|
||||
})?;
|
||||
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
||||
res.into()
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
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>> {
|
||||
|
|
@ -665,7 +665,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
location: Location,
|
||||
) {
|
||||
trace!("visit_statement: {:?}", statement);
|
||||
if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
|
||||
if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind {
|
||||
let place_ty: Ty<'tcx> = place
|
||||
.ty(&self.local_decls, self.tcx)
|
||||
.ty;
|
||||
|
|
@ -673,7 +673,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *place {
|
||||
trace!("checking whether {:?} can be stored to {:?}", value, local);
|
||||
if self.can_const_prop[local] {
|
||||
|
|
|
|||
|
|
@ -94,11 +94,13 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
// That use of the source must be an assignment.
|
||||
match statement.kind {
|
||||
StatementKind::Assign(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
},
|
||||
box Rvalue::Use(ref operand)
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(ref operand)
|
||||
)
|
||||
) if local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
Operand::Copy(ref src_place) |
|
||||
|
|
@ -148,24 +150,28 @@ fn eliminate_self_assignments(
|
|||
if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
},
|
||||
box Rvalue::Use(Operand::Copy(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: None,
|
||||
})),
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Copy(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: box [],
|
||||
})),
|
||||
)
|
||||
) |
|
||||
StatementKind::Assign(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
},
|
||||
box Rvalue::Use(Operand::Move(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: None,
|
||||
})),
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: box [],
|
||||
})),
|
||||
)
|
||||
) if local == dest_local && dest_local == src_local => {}
|
||||
_ => {
|
||||
continue;
|
||||
|
|
@ -194,7 +200,7 @@ impl<'tcx> Action<'tcx> {
|
|||
// The source must be a local.
|
||||
let src_local = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *src_place {
|
||||
local
|
||||
} else {
|
||||
|
|
@ -351,11 +357,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
|||
match *operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) if local == self.dest_local => {}
|
||||
_ => return,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
|||
for bb in basic_blocks {
|
||||
bb.expand_statements(|stmt| {
|
||||
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
|
||||
if let StatementKind::Assign(_, ref rhs) = stmt.kind {
|
||||
if let Rvalue::Aggregate(ref kind, _) = **rhs {
|
||||
if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind {
|
||||
if let Rvalue::Aggregate(ref kind, _) = *rhs {
|
||||
// FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
|
||||
if let AggregateKind::Array(_) = **kind {
|
||||
return None;
|
||||
|
|
@ -28,7 +28,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
|||
let stmt = stmt.replace_nop();
|
||||
let source_info = stmt.source_info;
|
||||
let (lhs, kind, operands) = match stmt.kind {
|
||||
StatementKind::Assign(lhs, box rvalue) => {
|
||||
StatementKind::Assign(box(lhs, rvalue)) => {
|
||||
match rvalue {
|
||||
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
|
||||
_ => bug!()
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
||||
match p {
|
||||
&Projection {
|
||||
elem: ProjectionElem::Field(idx, _), ..
|
||||
} => idx == field,
|
||||
_ => false
|
||||
}
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||
ProjectionElem::Field(idx, _) => *idx == field,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
||||
match p {
|
||||
&Projection {
|
||||
elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
|
||||
} => offset == index,
|
||||
&Projection {
|
||||
elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
|
||||
} => size - offset == index,
|
||||
_ => false
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
|
||||
*offset == index
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
|
||||
size - offset == index
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
||||
match p {
|
||||
&Projection { elem: ProjectionElem::Deref, .. } => true,
|
||||
_ => false
|
||||
}
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
|
||||
*e == ProjectionElem::Deref
|
||||
})
|
||||
}
|
||||
|
||||
fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
||||
match p {
|
||||
&Projection {
|
||||
elem: ProjectionElem::Downcast(_, idx), ..
|
||||
} => idx == variant,
|
||||
_ => false
|
||||
}
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||
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");
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -107,10 +107,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
|||
if place.base == PlaceBase::Local(self_arg()) {
|
||||
replace_base(place, Place {
|
||||
base: PlaceBase::Local(self_arg()),
|
||||
projection: Some(Box::new(Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
})),
|
||||
projection: Box::new([ProjectionElem::Deref]),
|
||||
});
|
||||
} else {
|
||||
self.super_place(place, context, location);
|
||||
|
|
@ -137,10 +134,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
if place.base == PlaceBase::Local(self_arg()) {
|
||||
replace_base(place, Place {
|
||||
base: PlaceBase::Local(self_arg()),
|
||||
projection: Some(Box::new(Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
|
||||
})),
|
||||
projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
|
||||
});
|
||||
} else {
|
||||
self.super_place(place, context, location);
|
||||
|
|
@ -149,13 +143,12 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
}
|
||||
|
||||
fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
|
||||
let mut projection = &mut place.projection;
|
||||
while let Some(box proj) = projection {
|
||||
projection = &mut proj.base;
|
||||
}
|
||||
|
||||
place.base = new_base.base;
|
||||
*projection = new_base.projection;
|
||||
|
||||
let mut new_projection = new_base.projection.to_vec();
|
||||
new_projection.append(&mut place.projection.to_vec());
|
||||
|
||||
place.projection = new_projection.into_boxed_slice();
|
||||
}
|
||||
|
||||
fn self_arg() -> Local {
|
||||
|
|
@ -210,13 +203,12 @@ impl TransformVisitor<'tcx> {
|
|||
fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||
let self_place = Place::from(self_arg());
|
||||
let base = self_place.downcast_unnamed(variant_index);
|
||||
let field = Projection {
|
||||
base: base.projection,
|
||||
elem: ProjectionElem::Field(Field::new(idx), ty),
|
||||
};
|
||||
let mut projection = base.projection.to_vec();
|
||||
projection.push(ProjectionElem::Field(Field::new(idx), ty));
|
||||
|
||||
Place {
|
||||
base: base.base,
|
||||
projection: Some(Box::new(field)),
|
||||
projection: projection.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +217,10 @@ impl TransformVisitor<'tcx> {
|
|||
let self_place = Place::from(self_arg());
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc },
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: box self_place,
|
||||
variant_index: state_disc,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -238,7 +233,7 @@ impl TransformVisitor<'tcx> {
|
|||
let self_place = Place::from(self_arg());
|
||||
let assign = Statement {
|
||||
source_info: source_info(body),
|
||||
kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)),
|
||||
kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))),
|
||||
};
|
||||
(assign, temp)
|
||||
}
|
||||
|
|
@ -296,8 +291,12 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
|||
// We must assign the value first in case it gets declared dead below
|
||||
data.statements.push(Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(Place::RETURN_PLACE,
|
||||
box self.make_state(state_idx, v)),
|
||||
kind: StatementKind::Assign(
|
||||
box(
|
||||
Place::return_place(),
|
||||
self.make_state(state_idx, v)
|
||||
)
|
||||
),
|
||||
});
|
||||
let state = if let Some(resume) = resume { // Yield
|
||||
let state = 3 + self.suspension_points.len();
|
||||
|
|
@ -848,7 +847,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
|
|||
kind: TerminatorKind::Drop {
|
||||
location: Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
},
|
||||
target,
|
||||
unwind
|
||||
|
|
@ -937,7 +936,7 @@ fn create_generator_drop_shim<'tcx>(
|
|||
// Alias tracking must know we changed the type
|
||||
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())),
|
||||
kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -425,22 +425,20 @@ impl Inliner<'tcx> {
|
|||
// writes to `i`. To prevent this we need to create a temporary
|
||||
// borrow of the place and pass the destination as `*temp` instead.
|
||||
fn dest_needs_borrow(place: &Place<'_>) -> bool {
|
||||
place.iterate(|place_base, place_projection| {
|
||||
for proj in place_projection {
|
||||
match proj.elem {
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Index(_) => return true,
|
||||
_ => {}
|
||||
}
|
||||
for elem in place.projection.iter() {
|
||||
match elem {
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Index(_) => return true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match place_base {
|
||||
// Static variables need a borrow because the callee
|
||||
// might modify the same static.
|
||||
PlaceBase::Static(_) => true,
|
||||
_ => false
|
||||
}
|
||||
})
|
||||
match place.base {
|
||||
// Static variables need a borrow because the callee
|
||||
// might modify the same static.
|
||||
PlaceBase::Static(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
let dest = if dest_needs_borrow(&destination.0) {
|
||||
|
|
@ -459,7 +457,7 @@ impl Inliner<'tcx> {
|
|||
|
||||
let stmt = Statement {
|
||||
source_info: callsite.location,
|
||||
kind: StatementKind::Assign(tmp.clone(), box dest)
|
||||
kind: StatementKind::Assign(box(tmp.clone(), dest))
|
||||
};
|
||||
caller_body[callsite.bb]
|
||||
.statements.push(stmt);
|
||||
|
|
@ -591,7 +589,7 @@ impl Inliner<'tcx> {
|
|||
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) = arg {
|
||||
if caller_body.local_kind(local) == LocalKind::Temp {
|
||||
// Reuse the operand if it's a temporary already
|
||||
|
|
@ -610,7 +608,7 @@ impl Inliner<'tcx> {
|
|||
|
||||
let stmt = Statement {
|
||||
source_info: callsite.location,
|
||||
kind: StatementKind::Assign(Place::from(arg_tmp), box arg),
|
||||
kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)),
|
||||
};
|
||||
caller_body[callsite.bb].statements.push(stmt);
|
||||
arg_tmp
|
||||
|
|
@ -660,7 +658,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||
match self.destination {
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} => {
|
||||
*local = l;
|
||||
return;
|
||||
|
|
@ -684,7 +682,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} => {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
|
|
|
|||
|
|
@ -43,12 +43,21 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
|||
let new_place = match *rvalue {
|
||||
Rvalue::Ref(_, _, Place {
|
||||
ref mut base,
|
||||
projection: Some(ref mut projection),
|
||||
}) => Place {
|
||||
// Replace with dummy
|
||||
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
|
||||
projection: projection.base.take(),
|
||||
},
|
||||
projection: ref mut projection @ box [.., _],
|
||||
}) => {
|
||||
if let box [proj_l @ .., proj_r] = projection {
|
||||
let place = Place {
|
||||
// Replace with dummy
|
||||
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
|
||||
projection: proj_l.to_vec().into_boxed_slice(),
|
||||
};
|
||||
*projection = vec![proj_r.clone()].into_boxed_slice();
|
||||
|
||||
place
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
_ => bug!("Detected `&*` but didn't find `&*`!"),
|
||||
};
|
||||
*rvalue = Rvalue::Use(Operand::Copy(new_place))
|
||||
|
|
@ -83,13 +92,11 @@ impl OptimizationFinder<'b, 'tcx> {
|
|||
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
if let Rvalue::Ref(_, _, Place {
|
||||
ref base,
|
||||
projection: Some(ref projection),
|
||||
}) = *rvalue {
|
||||
if let ProjectionElem::Deref = projection.elem {
|
||||
if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() {
|
||||
self.optimizations.and_stars.insert(location);
|
||||
}
|
||||
base,
|
||||
projection: box [proj_base @ .., ProjectionElem::Deref],
|
||||
}) = rvalue {
|
||||
if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
|
||||
self.optimizations.and_stars.insert(location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
span,
|
||||
scope: OUTERMOST_SOURCE_SCOPE
|
||||
},
|
||||
kind: StatementKind::Assign(Place::from(dest), box rvalue)
|
||||
kind: StatementKind::Assign(box(Place::from(dest), rvalue))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -222,10 +222,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
// First, take the Rvalue or Call out of the source MIR,
|
||||
// or duplicate it, depending on keep_original.
|
||||
if loc.statement_index < no_stmts {
|
||||
let (rvalue, source_info) = {
|
||||
let (mut rvalue, source_info) = {
|
||||
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
||||
let rhs = match statement.kind {
|
||||
StatementKind::Assign(_, ref mut rhs) => rhs,
|
||||
StatementKind::Assign(box(_, ref mut rhs)) => rhs,
|
||||
_ => {
|
||||
span_bug!(statement.source_info.span, "{:?} is not an assignment",
|
||||
statement);
|
||||
|
|
@ -235,12 +235,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
(if self.keep_original {
|
||||
rhs.clone()
|
||||
} else {
|
||||
let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
|
||||
let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
|
||||
mem::replace(rhs, unit)
|
||||
}, statement.source_info)
|
||||
};
|
||||
|
||||
let mut rvalue = *rvalue;
|
||||
self.visit_rvalue(&mut rvalue, loc);
|
||||
self.assign(new_temp, rvalue, source_info.span);
|
||||
} else {
|
||||
|
|
@ -318,7 +317,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
ty,
|
||||
def_id,
|
||||
}),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}
|
||||
};
|
||||
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
||||
|
|
@ -326,7 +325,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
Candidate::Ref(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
|
||||
StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = place.base.ty(local_decls).ty;
|
||||
let span = statement.source_info.span;
|
||||
|
|
@ -334,9 +333,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
Operand::Move(Place {
|
||||
base: mem::replace(
|
||||
&mut place.base,
|
||||
promoted_place(ty, span).base
|
||||
promoted_place(ty, span).base,
|
||||
),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
})
|
||||
}
|
||||
_ => bug!()
|
||||
|
|
@ -345,7 +344,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
Candidate::Repeat(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
|
||||
StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => {
|
||||
let ty = operand.ty(local_decls, self.tcx);
|
||||
let span = statement.source_info.span;
|
||||
mem::replace(
|
||||
|
|
@ -420,10 +419,10 @@ pub fn promote_candidates<'tcx>(
|
|||
Candidate::Repeat(Location { block, statement_index }) |
|
||||
Candidate::Ref(Location { block, statement_index }) => {
|
||||
match body[block].statements[statement_index].kind {
|
||||
StatementKind::Assign(Place {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
}, _) => {
|
||||
projection: box [],
|
||||
}, _)) => {
|
||||
if temps[local] == TempState::PromotedOut {
|
||||
// Already promoted.
|
||||
continue;
|
||||
|
|
@ -473,10 +472,10 @@ pub fn promote_candidates<'tcx>(
|
|||
for block in body.basic_blocks_mut() {
|
||||
block.statements.retain(|statement| {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(Place {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: None,
|
||||
}, _) |
|
||||
projection: box [],
|
||||
}, _)) |
|
||||
StatementKind::StorageLive(index) |
|
||||
StatementKind::StorageDead(index) => {
|
||||
!promoted(index)
|
||||
|
|
@ -488,7 +487,7 @@ pub fn promote_candidates<'tcx>(
|
|||
match terminator.kind {
|
||||
TerminatorKind::Drop { location: Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}, target, .. } => {
|
||||
if promoted(index) {
|
||||
terminator.kind = TerminatorKind::Goto {
|
||||
|
|
|
|||
|
|
@ -187,26 +187,28 @@ trait Qualif {
|
|||
cx: &ConstCx<'_, 'tcx>,
|
||||
place: PlaceRef<'_, 'tcx>,
|
||||
) -> 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 {
|
||||
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, &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),
|
||||
ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local),
|
||||
}
|
||||
} else {
|
||||
bug!("This should be called if projection is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,24 +223,24 @@ trait Qualif {
|
|||
match place {
|
||||
PlaceRef {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => Self::in_local(cx, *local),
|
||||
PlaceRef {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => bug!("qualifying already promoted MIR"),
|
||||
PlaceRef {
|
||||
base: PlaceBase::Static(static_),
|
||||
projection: None,
|
||||
projection: [],
|
||||
} => {
|
||||
Self::in_static(cx, static_)
|
||||
},
|
||||
PlaceRef {
|
||||
base: _,
|
||||
projection: Some(_),
|
||||
projection: [.., _],
|
||||
} => Self::in_projection(cx, place),
|
||||
}
|
||||
}
|
||||
|
|
@ -289,13 +291,13 @@ trait Qualif {
|
|||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let Some(ref proj) = place.projection {
|
||||
if let ProjectionElem::Deref = proj.elem {
|
||||
let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty;
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if ProjectionElem::Deref == *elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.sty {
|
||||
return Self::in_place(cx, PlaceRef {
|
||||
base: &place.base,
|
||||
projection: &proj.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -453,30 +455,32 @@ impl Qualif for IsNotPromotable {
|
|||
cx: &ConstCx<'_, 'tcx>,
|
||||
place: PlaceRef<'_, 'tcx>,
|
||||
) -> 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::Deref |
|
||||
ProjectionElem::Downcast(..) => return true,
|
||||
ProjectionElem::ConstantIndex {..} |
|
||||
ProjectionElem::Subslice {..} |
|
||||
ProjectionElem::Index(_) => {}
|
||||
|
||||
ProjectionElem::ConstantIndex {..} |
|
||||
ProjectionElem::Subslice {..} |
|
||||
ProjectionElem::Index(_) => {}
|
||||
|
||||
ProjectionElem::Field(..) => {
|
||||
if cx.mode == Mode::NonConstFn {
|
||||
let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty;
|
||||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
// No promotion of union field accesses.
|
||||
if def.is_union() {
|
||||
return true;
|
||||
ProjectionElem::Field(..) => {
|
||||
if cx.mode == Mode::NonConstFn {
|
||||
let base_ty = Place::ty_from(place.base, proj_base, cx.body, cx.tcx).ty;
|
||||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
// No promotion of union field accesses.
|
||||
if def.is_union() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self::in_projection_structurally(cx, place)
|
||||
Self::in_projection_structurally(cx, place)
|
||||
} else {
|
||||
bug!("This should be called if projection is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
|
||||
|
|
@ -806,23 +810,18 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
// We might have a candidate for promotion.
|
||||
let candidate = Candidate::Ref(location);
|
||||
// Start by traversing to the "base", with non-deref projections removed.
|
||||
let mut place_projection = &place.projection;
|
||||
while let Some(proj) = place_projection {
|
||||
if proj.elem == ProjectionElem::Deref {
|
||||
break;
|
||||
}
|
||||
place_projection = &proj.base;
|
||||
}
|
||||
let deref_proj =
|
||||
place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref);
|
||||
|
||||
debug!(
|
||||
"qualify_consts: promotion candidate: place={:?} {:?}",
|
||||
place.base, place_projection
|
||||
place.base, deref_proj
|
||||
);
|
||||
// We can only promote interior borrows of promotable temps (non-temps
|
||||
// don't get promoted anyway).
|
||||
// (If we bailed out of the loop due to a `Deref` above, we will definitely
|
||||
// not enter the conditional here.)
|
||||
if let (PlaceBase::Local(local), None) = (&place.base, place_projection) {
|
||||
if let (PlaceBase::Local(local), None) = (&place.base, deref_proj) {
|
||||
if self.body.local_kind(*local) == LocalKind::Temp {
|
||||
debug!("qualify_consts: promotion candidate: local={:?}", local);
|
||||
// The borrowed place doesn't have `HasMutInterior`
|
||||
|
|
@ -858,27 +857,27 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
_ => {},
|
||||
}
|
||||
|
||||
let mut dest_projection = &dest.projection;
|
||||
let mut dest_projection = &dest.projection[..];
|
||||
let index = loop {
|
||||
match (&dest.base, dest_projection) {
|
||||
// We treat all locals equal in constants
|
||||
(&PlaceBase::Local(index), None) => break index,
|
||||
(&PlaceBase::Local(index), []) => break index,
|
||||
// projections are transparent for assignments
|
||||
// we qualify the entire destination at once, even if just a field would have
|
||||
// stricter qualification
|
||||
(base, Some(proj)) => {
|
||||
(base, [proj_base @ .., _]) => {
|
||||
// Catch more errors in the destination. `visit_place` also checks various
|
||||
// projection rules like union field access and raw pointer deref
|
||||
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
|
||||
self.visit_place_base(base, context, location);
|
||||
self.visit_projection(base, proj, context, location);
|
||||
dest_projection = &proj.base;
|
||||
self.visit_projection(base, dest_projection, context, location);
|
||||
dest_projection = proj_base;
|
||||
},
|
||||
(&PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}), None) => bug!("promoteds don't exist yet during promotion"),
|
||||
(&PlaceBase::Static(box Static{ kind: _, .. }), None) => {
|
||||
}), []) => bug!("promoteds don't exist yet during promotion"),
|
||||
(&PlaceBase::Static(box Static{ kind: _, .. }), []) => {
|
||||
// Catch more errors in the destination. `visit_place` also checks that we
|
||||
// do not try to access statics from constants or try to mutate statics
|
||||
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
|
||||
|
|
@ -983,23 +982,25 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
for candidate in &self.promotion_candidates {
|
||||
match *candidate {
|
||||
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
if let StatementKind::Assign(_, box Rvalue::Repeat(
|
||||
if let StatementKind::Assign(box(_, Rvalue::Repeat(
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}),
|
||||
_
|
||||
)) = self.body[bb].statements[stmt_idx].kind {
|
||||
))) = self.body[bb].statements[stmt_idx].kind {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
}
|
||||
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
if let StatementKind::Assign(
|
||||
_,
|
||||
box Rvalue::Ref(_, _, Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: None,
|
||||
})
|
||||
box(
|
||||
_,
|
||||
Rvalue::Ref(_, _, Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
})
|
||||
)
|
||||
) = self.body[bb].statements[stmt_idx].kind {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
|
|
@ -1084,7 +1085,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
fn visit_projection(
|
||||
&mut self,
|
||||
place_base: &PlaceBase<'tcx>,
|
||||
proj: &Projection<'tcx>,
|
||||
proj: &[PlaceElem<'tcx>],
|
||||
context: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
|
|
@ -1093,62 +1094,65 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
proj, context, location,
|
||||
);
|
||||
self.super_projection(place_base, proj, context, location);
|
||||
match proj.elem {
|
||||
ProjectionElem::Deref => {
|
||||
if context.is_mutating_use() {
|
||||
// `not_const` errors out in const contexts
|
||||
self.not_const()
|
||||
}
|
||||
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
|
||||
match self.mode {
|
||||
Mode::NonConstFn => {},
|
||||
_ => {
|
||||
if let ty::RawPtr(_) = base_ty.sty {
|
||||
if !self.tcx.features().const_raw_ptr_deref {
|
||||
emit_feature_err(
|
||||
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
|
||||
self.span, GateIssue::Language,
|
||||
&format!(
|
||||
"dereferencing raw pointers in {}s is unstable",
|
||||
self.mode,
|
||||
),
|
||||
);
|
||||
|
||||
if let [proj_base @ .., elem] = proj {
|
||||
match elem {
|
||||
ProjectionElem::Deref => {
|
||||
if context.is_mutating_use() {
|
||||
// `not_const` errors out in const contexts
|
||||
self.not_const()
|
||||
}
|
||||
let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
|
||||
match self.mode {
|
||||
Mode::NonConstFn => {},
|
||||
_ => {
|
||||
if let ty::RawPtr(_) = base_ty.sty {
|
||||
if !self.tcx.features().const_raw_ptr_deref {
|
||||
emit_feature_err(
|
||||
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
|
||||
self.span, GateIssue::Language,
|
||||
&format!(
|
||||
"dereferencing raw pointers in {}s is unstable",
|
||||
self.mode,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectionElem::ConstantIndex {..} |
|
||||
ProjectionElem::Subslice {..} |
|
||||
ProjectionElem::Field(..) |
|
||||
ProjectionElem::Index(_) => {
|
||||
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
|
||||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
if def.is_union() {
|
||||
match self.mode {
|
||||
Mode::ConstFn => {
|
||||
if !self.tcx.features().const_fn_union {
|
||||
emit_feature_err(
|
||||
&self.tcx.sess.parse_sess, sym::const_fn_union,
|
||||
self.span, GateIssue::Language,
|
||||
"unions in const fn are unstable",
|
||||
);
|
||||
}
|
||||
},
|
||||
ProjectionElem::ConstantIndex {..} |
|
||||
ProjectionElem::Subslice {..} |
|
||||
ProjectionElem::Field(..) |
|
||||
ProjectionElem::Index(_) => {
|
||||
let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
|
||||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
if def.is_union() {
|
||||
match self.mode {
|
||||
Mode::ConstFn => {
|
||||
if !self.tcx.features().const_fn_union {
|
||||
emit_feature_err(
|
||||
&self.tcx.sess.parse_sess, sym::const_fn_union,
|
||||
self.span, GateIssue::Language,
|
||||
"unions in const fn are unstable",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
| Mode::NonConstFn
|
||||
| Mode::Static
|
||||
| Mode::StaticMut
|
||||
| Mode::Const
|
||||
=> {},
|
||||
| Mode::NonConstFn
|
||||
| Mode::Static
|
||||
| Mode::StaticMut
|
||||
| Mode::Const
|
||||
=> {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectionElem::Downcast(..) => {
|
||||
self.not_const()
|
||||
ProjectionElem::Downcast(..) => {
|
||||
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.
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *place {
|
||||
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 {
|
||||
// Special-case reborrows.
|
||||
let mut reborrow_place = None;
|
||||
if let Some(ref proj) = place.projection {
|
||||
if let ProjectionElem::Deref = proj.elem {
|
||||
let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if *elem == ProjectionElem::Deref {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.sty {
|
||||
reborrow_place = Some(&proj.base);
|
||||
reborrow_place = Some(proj_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1204,9 +1208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
if let Some(proj) = proj {
|
||||
self.visit_projection(&place.base, proj, ctx, location);
|
||||
}
|
||||
self.visit_projection(&place.base, proj, ctx, location);
|
||||
} else {
|
||||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
|
@ -1477,7 +1479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
// conservatively, that drop elaboration will do.
|
||||
let needs_drop = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if NeedsDrop::in_local(self, local) {
|
||||
Some(self.body.local_decls[local].source_info.span)
|
||||
|
|
@ -1727,7 +1729,7 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
|
|||
TerminatorKind::Drop {
|
||||
location: Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
},
|
||||
target,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ fn check_statement(
|
|||
) -> McfResult {
|
||||
let span = statement.source_info.span;
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(place, rval) => {
|
||||
StatementKind::Assign(box(place, rval)) => {
|
||||
check_place(place, span)?;
|
||||
check_rvalue(tcx, body, rval, span)
|
||||
}
|
||||
|
|
@ -249,28 +249,26 @@ fn check_place(
|
|||
place: &Place<'tcx>,
|
||||
span: Span,
|
||||
) -> McfResult {
|
||||
place.iterate(|place_base, place_projection| {
|
||||
for proj in place_projection {
|
||||
match proj.elem {
|
||||
ProjectionElem::Downcast(..) => {
|
||||
return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
|
||||
}
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Deref
|
||||
| ProjectionElem::Field(..)
|
||||
| ProjectionElem::Index(_) => {}
|
||||
for elem in place.projection.iter() {
|
||||
match elem {
|
||||
ProjectionElem::Downcast(..) => {
|
||||
return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
|
||||
}
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Deref
|
||||
| ProjectionElem::Field(..)
|
||||
| ProjectionElem::Index(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
match place_base {
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
|
||||
Err((span, "cannot access `static` items in const fn".into()))
|
||||
}
|
||||
PlaceBase::Local(_)
|
||||
| PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
|
||||
match place.base {
|
||||
PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
|
||||
Err((span, "cannot access `static` items in const fn".into()))
|
||||
}
|
||||
})
|
||||
PlaceBase::Local(_)
|
||||
| PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_terminator(
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ impl RemoveNoopLandingPads {
|
|||
// These are all nops in a landing pad
|
||||
}
|
||||
|
||||
StatementKind::Assign(Place {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: None,
|
||||
}, box Rvalue::Use(_)) => {
|
||||
projection: box [],
|
||||
}, Rvalue::Use(_))) => {
|
||||
// Writing to a local (e.g., a drop flag) does not
|
||||
// turn a landing pad to a non-nop
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,11 +120,11 @@ fn each_block<'tcx, O>(
|
|||
let peek_arg_place = match args[0] {
|
||||
mir::Operand::Copy(ref place @ mir::Place {
|
||||
base: mir::PlaceBase::Local(_),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) |
|
||||
mir::Operand::Move(ref place @ mir::Place {
|
||||
base: mir::PlaceBase::Local(_),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) => Some(place),
|
||||
_ => None,
|
||||
};
|
||||
|
|
@ -150,7 +150,7 @@ fn each_block<'tcx, O>(
|
|||
for (j, stmt) in statements.iter().enumerate() {
|
||||
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
|
||||
let (place, rvalue) = match stmt.kind {
|
||||
mir::StatementKind::Assign(ref place, ref rvalue) => {
|
||||
mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
|
||||
(place, rvalue)
|
||||
}
|
||||
mir::StatementKind::FakeRead(..) |
|
||||
|
|
@ -166,7 +166,7 @@ fn each_block<'tcx, O>(
|
|||
};
|
||||
|
||||
if place == peek_arg_place {
|
||||
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
|
||||
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
|
||||
// Okay, our search is over.
|
||||
match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
|
||||
LookupResult::Exact(peek_mpi) => {
|
||||
|
|
|
|||
|
|
@ -61,14 +61,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
|
||||
if let Some(ref proj) = src_place.projection {
|
||||
if let box [proj_base @ .., elem] = &src_place.projection {
|
||||
if let ProjectionElem::ConstantIndex{offset: _,
|
||||
min_length: _,
|
||||
from_end: false} = proj.elem {
|
||||
from_end: false} = elem {
|
||||
// no need to transformation
|
||||
} else {
|
||||
let place_ty =
|
||||
Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).ty;
|
||||
Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Array(item_ty, const_size) = place_ty.sty {
|
||||
if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
|
||||
assert!(size <= u32::max_value() as u64,
|
||||
|
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
location,
|
||||
dst_place,
|
||||
&src_place.base,
|
||||
proj,
|
||||
&src_place.projection,
|
||||
item_ty,
|
||||
size as u32,
|
||||
);
|
||||
|
|
@ -97,73 +97,76 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
location: Location,
|
||||
dst_place: &Place<'tcx>,
|
||||
base: &PlaceBase<'tcx>,
|
||||
proj: &Projection<'tcx>,
|
||||
proj: &[PlaceElem<'tcx>],
|
||||
item_ty: &'tcx ty::TyS<'tcx>,
|
||||
size: u32) {
|
||||
match proj.elem {
|
||||
// uniforms statements like_10 = move _2[:-1];
|
||||
ProjectionElem::Subslice{from, to} => {
|
||||
self.patch.make_nop(location);
|
||||
let temps : Vec<_> = (from..(size-to)).map(|i| {
|
||||
let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span);
|
||||
self.patch.add_statement(location, StatementKind::StorageLive(temp));
|
||||
if let [proj_base @ .., elem] = proj {
|
||||
match elem {
|
||||
// uniforms statements like_10 = move _2[:-1];
|
||||
ProjectionElem::Subslice{from, to} => {
|
||||
self.patch.make_nop(location);
|
||||
let temps : Vec<_> = (*from..(size-*to)).map(|i| {
|
||||
let temp =
|
||||
self.patch.new_temp(item_ty, self.body.source_info(location).span);
|
||||
self.patch.add_statement(location, StatementKind::StorageLive(temp));
|
||||
|
||||
let mut projection = proj_base.to_vec();
|
||||
projection.push(ProjectionElem::ConstantIndex {
|
||||
offset: i,
|
||||
min_length: size,
|
||||
from_end: false,
|
||||
});
|
||||
self.patch.add_assign(location,
|
||||
Place::from(temp),
|
||||
Rvalue::Use(
|
||||
Operand::Move(
|
||||
Place {
|
||||
base: base.clone(),
|
||||
projection: projection.into_boxed_slice(),
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
temp
|
||||
}).collect();
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
dst_place.clone(),
|
||||
Rvalue::Aggregate(
|
||||
box AggregateKind::Array(item_ty),
|
||||
temps.iter().map(
|
||||
|x| Operand::Move(Place::from(*x))
|
||||
).collect()
|
||||
)
|
||||
);
|
||||
for temp in temps {
|
||||
self.patch.add_statement(location, StatementKind::StorageDead(temp));
|
||||
}
|
||||
}
|
||||
// uniforms statements like _11 = move _2[-1 of 1];
|
||||
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
|
||||
self.patch.make_nop(location);
|
||||
|
||||
let mut projection = proj_base.to_vec();
|
||||
projection.push(ProjectionElem::ConstantIndex {
|
||||
offset: size - offset,
|
||||
min_length: size,
|
||||
from_end: false,
|
||||
});
|
||||
self.patch.add_assign(location,
|
||||
Place::from(temp),
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(
|
||||
Operand::Move(
|
||||
Place {
|
||||
base: base.clone(),
|
||||
projection: Some(box Projection {
|
||||
base: proj.base.clone(),
|
||||
elem: ProjectionElem::ConstantIndex {
|
||||
offset: i,
|
||||
min_length: size,
|
||||
from_end: false,
|
||||
}
|
||||
}),
|
||||
projection: projection.into_boxed_slice(),
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
temp
|
||||
}).collect();
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
dst_place.clone(),
|
||||
Rvalue::Aggregate(
|
||||
box AggregateKind::Array(item_ty),
|
||||
temps.iter().map(
|
||||
|x| Operand::Move(Place::from(*x))
|
||||
).collect()
|
||||
)
|
||||
);
|
||||
for temp in temps {
|
||||
self.patch.add_statement(location, StatementKind::StorageDead(temp));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// uniforms statements like _11 = move _2[-1 of 1];
|
||||
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
|
||||
self.patch.make_nop(location);
|
||||
self.patch.add_assign(location,
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(
|
||||
Operand::Move(
|
||||
Place {
|
||||
base: base.clone(),
|
||||
projection: Some(box Projection {
|
||||
base: proj.base.clone(),
|
||||
elem: ProjectionElem::ConstantIndex {
|
||||
offset: size - offset,
|
||||
min_length: size,
|
||||
from_end: false,
|
||||
},
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -197,12 +200,12 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
|||
|
||||
for candidate in &visitor.candidates {
|
||||
let statement = &body[candidate.block].statements[candidate.statement_index];
|
||||
if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval {
|
||||
if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
|
||||
let items : Vec<_> = items.iter().map(|item| {
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
projection: box [],
|
||||
}) = item {
|
||||
let local_use = &visitor.locals_use[*local];
|
||||
let opt_index_and_place =
|
||||
|
|
@ -269,16 +272,17 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
}
|
||||
patch.make_nop(candidate);
|
||||
let size = opt_size.unwrap() as u32;
|
||||
patch.add_assign(candidate,
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(
|
||||
Operand::Move(
|
||||
Place {
|
||||
base: src_place.base.clone(),
|
||||
projection: Some(box Projection {
|
||||
base: src_place.projection.clone(),
|
||||
elem: ProjectionElem::Subslice{
|
||||
from: min, to: size - max - 1}})})));
|
||||
|
||||
let mut projection = src_place.projection.to_vec();
|
||||
projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
|
||||
patch.add_assign(
|
||||
candidate,
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: src_place.base.clone(),
|
||||
projection: projection.into_boxed_slice(),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,23 +293,34 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
if block.statements.len() > location.statement_index {
|
||||
let statement = &block.statements[location.statement_index];
|
||||
if let StatementKind::Assign(
|
||||
Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: None,
|
||||
},
|
||||
box Rvalue::Use(Operand::Move(Place {
|
||||
base,
|
||||
projection: Some(box Projection {
|
||||
base: proj_base,
|
||||
elem: ProjectionElem::ConstantIndex {
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: _,
|
||||
projection: box [.., ProjectionElem::ConstantIndex {
|
||||
offset, min_length: _, from_end: false
|
||||
}
|
||||
}),
|
||||
}))) = &statement.kind {
|
||||
return Some((*offset, PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}))
|
||||
}],
|
||||
})),
|
||||
)
|
||||
) = &statement.kind {
|
||||
// FIXME remove once we can use slices patterns
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
_,
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base,
|
||||
projection: box [proj_base @ .., _],
|
||||
})),
|
||||
)
|
||||
) = &statement.kind {
|
||||
return Some((*offset, PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
if adt_def.is_enum() {
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: lhs.clone(),
|
||||
place: box(lhs.clone()),
|
||||
variant_index,
|
||||
},
|
||||
source_info,
|
||||
|
|
@ -39,7 +39,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
let variant_index = VariantIdx::new(0);
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: lhs.clone(),
|
||||
place: box(lhs.clone()),
|
||||
variant_index,
|
||||
},
|
||||
source_info,
|
||||
|
|
@ -70,7 +70,7 @@ pub fn expand_aggregate<'tcx>(
|
|||
};
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
|
||||
kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))),
|
||||
}
|
||||
}).chain(set_discriminant)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
|
|||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
{
|
||||
let mut place_projection = &place.projection;
|
||||
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||
let proj_base = &place.projection[..i];
|
||||
|
||||
while let Some(proj) = place_projection {
|
||||
match proj.elem {
|
||||
match elem {
|
||||
// encountered a Deref, which is ABI-aligned
|
||||
ProjectionElem::Deref => break,
|
||||
ProjectionElem::Field(..) => {
|
||||
let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty;
|
||||
let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
|
||||
match ty.sty {
|
||||
ty::Adt(def, _) if def.repr.packed() => {
|
||||
return true
|
||||
|
|
@ -55,7 +55,6 @@ where
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
place_projection = &proj.base;
|
||||
}
|
||||
|
||||
false
|
||||
|
|
|
|||
|
|
@ -586,10 +586,7 @@ where
|
|||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
Place {
|
||||
base: PlaceBase::Local(cur),
|
||||
projection: Some(Box::new(Projection {
|
||||
base: None,
|
||||
elem: ProjectionElem::Deref,
|
||||
})),
|
||||
projection: Box::new([ProjectionElem::Deref]),
|
||||
}
|
||||
),
|
||||
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
|
||||
|
|
@ -981,7 +978,7 @@ where
|
|||
fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
|
||||
Statement {
|
||||
source_info: self.source_info,
|
||||
kind: StatementKind::Assign(lhs.clone(), box rhs)
|
||||
kind: StatementKind::Assign(box(lhs.clone(), rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
}
|
||||
|
||||
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
|
||||
self.add_statement(loc, StatementKind::Assign(place, box rv));
|
||||
self.add_statement(loc, StatementKind::Assign(box(place, rv)));
|
||||
}
|
||||
|
||||
pub fn make_nop(&mut self, loc: Location) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue