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 smallvec::SmallVec;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||||
use std::iter::FusedIterator;
|
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
@ -1548,7 +1547,7 @@ pub struct Statement<'tcx> {
|
||||||
|
|
||||||
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
|
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
static_assert_size!(Statement<'_>, 56);
|
static_assert_size!(Statement<'_>, 32);
|
||||||
|
|
||||||
impl Statement<'_> {
|
impl Statement<'_> {
|
||||||
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
|
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
|
||||||
|
|
@ -1569,7 +1568,7 @@ impl Statement<'_> {
|
||||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
|
||||||
pub enum StatementKind<'tcx> {
|
pub enum StatementKind<'tcx> {
|
||||||
/// Write the RHS Rvalue to the LHS Place.
|
/// Write the RHS Rvalue to the LHS Place.
|
||||||
Assign(Place<'tcx>, Box<Rvalue<'tcx>>),
|
Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
|
||||||
|
|
||||||
/// This represents all the reading that a pattern match may do
|
/// This represents all the reading that a pattern match may do
|
||||||
/// (e.g., inspecting constants and discriminant values), and the
|
/// (e.g., inspecting constants and discriminant values), and the
|
||||||
|
|
@ -1578,10 +1577,10 @@ pub enum StatementKind<'tcx> {
|
||||||
///
|
///
|
||||||
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
|
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
|
||||||
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
|
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
|
||||||
FakeRead(FakeReadCause, Place<'tcx>),
|
FakeRead(FakeReadCause, Box<Place<'tcx>>),
|
||||||
|
|
||||||
/// Write the discriminant for a variant to the enum Place.
|
/// Write the discriminant for a variant to the enum Place.
|
||||||
SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx },
|
SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
|
||||||
|
|
||||||
/// Start a live range for the storage of the local.
|
/// Start a live range for the storage of the local.
|
||||||
StorageLive(Local),
|
StorageLive(Local),
|
||||||
|
|
@ -1598,7 +1597,7 @@ pub enum StatementKind<'tcx> {
|
||||||
/// by miri and only generated when "-Z mir-emit-retag" is passed.
|
/// by miri and only generated when "-Z mir-emit-retag" is passed.
|
||||||
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
|
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
|
||||||
/// for more details.
|
/// for more details.
|
||||||
Retag(RetagKind, Place<'tcx>),
|
Retag(RetagKind, Box<Place<'tcx>>),
|
||||||
|
|
||||||
/// Encodes a user's type ascription. These need to be preserved
|
/// Encodes a user's type ascription. These need to be preserved
|
||||||
/// intact so that NLL can respect them. For example:
|
/// intact so that NLL can respect them. For example:
|
||||||
|
|
@ -1612,7 +1611,7 @@ pub enum StatementKind<'tcx> {
|
||||||
/// - `Contravariant` -- requires that `T_y :> T`
|
/// - `Contravariant` -- requires that `T_y :> T`
|
||||||
/// - `Invariant` -- requires that `T_y == T`
|
/// - `Invariant` -- requires that `T_y == T`
|
||||||
/// - `Bivariant` -- no effect
|
/// - `Bivariant` -- no effect
|
||||||
AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>),
|
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
|
||||||
|
|
||||||
/// No-op. Useful for deleting instructions without affecting statement indices.
|
/// No-op. Useful for deleting instructions without affecting statement indices.
|
||||||
Nop,
|
Nop,
|
||||||
|
|
@ -1676,7 +1675,7 @@ impl Debug for Statement<'_> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
use self::StatementKind::*;
|
use self::StatementKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
|
Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
|
||||||
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
|
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
|
||||||
Retag(ref kind, ref place) => write!(
|
Retag(ref kind, ref place) => write!(
|
||||||
fmt,
|
fmt,
|
||||||
|
|
@ -1697,7 +1696,7 @@ impl Debug for Statement<'_> {
|
||||||
InlineAsm(ref asm) => {
|
InlineAsm(ref asm) => {
|
||||||
write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
|
write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
|
||||||
}
|
}
|
||||||
AscribeUserType(ref place, ref variance, ref c_ty) => {
|
AscribeUserType(box(ref place, ref c_ty), ref variance) => {
|
||||||
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
||||||
}
|
}
|
||||||
Nop => write!(fmt, "nop"),
|
Nop => write!(fmt, "nop"),
|
||||||
|
|
@ -1717,7 +1716,7 @@ pub struct Place<'tcx> {
|
||||||
pub base: PlaceBase<'tcx>,
|
pub base: PlaceBase<'tcx>,
|
||||||
|
|
||||||
/// projection out of a place (access a field, deref a pointer, etc)
|
/// projection out of a place (access a field, deref a pointer, etc)
|
||||||
pub projection: Option<Box<Projection<'tcx>>>,
|
pub projection: Box<[PlaceElem<'tcx>]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
|
@ -1760,15 +1759,6 @@ impl_stable_hash_for!(struct Static<'tcx> {
|
||||||
def_id
|
def_id
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`.
|
|
||||||
#[derive(
|
|
||||||
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
|
|
||||||
)]
|
|
||||||
pub struct Projection<'tcx> {
|
|
||||||
pub base: Option<Box<Projection<'tcx>>>,
|
|
||||||
pub elem: PlaceElem<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
|
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
|
||||||
)]
|
)]
|
||||||
|
|
@ -1850,14 +1840,22 @@ newtype_index! {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct PlaceRef<'a, 'tcx> {
|
pub struct PlaceRef<'a, 'tcx> {
|
||||||
pub base: &'a PlaceBase<'tcx>,
|
pub base: &'a PlaceBase<'tcx>,
|
||||||
pub projection: &'a Option<Box<Projection<'tcx>>>,
|
pub projection: &'a [PlaceElem<'tcx>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Place<'tcx> {
|
impl<'tcx> Place<'tcx> {
|
||||||
pub const RETURN_PLACE: Place<'tcx> = Place {
|
// FIXME change this back to a const when projection is a shared slice.
|
||||||
base: PlaceBase::Local(RETURN_PLACE),
|
//
|
||||||
projection: None,
|
// pub const RETURN_PLACE: Place<'tcx> = Place {
|
||||||
};
|
// base: PlaceBase::Local(RETURN_PLACE),
|
||||||
|
// projection: &[],
|
||||||
|
// };
|
||||||
|
pub fn return_place() -> Place<'tcx> {
|
||||||
|
Place {
|
||||||
|
base: PlaceBase::Local(RETURN_PLACE),
|
||||||
|
projection: Box::new([]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
|
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||||
self.elem(ProjectionElem::Field(f, ty))
|
self.elem(ProjectionElem::Field(f, ty))
|
||||||
|
|
@ -1883,9 +1881,13 @@ impl<'tcx> Place<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
|
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
|
||||||
|
// FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
|
||||||
|
let mut projection = self.projection.into_vec();
|
||||||
|
projection.push(elem);
|
||||||
|
|
||||||
Place {
|
Place {
|
||||||
base: self.base,
|
base: self.base,
|
||||||
projection: Some(Box::new(Projection { base: self.projection, elem })),
|
projection: projection.into_boxed_slice(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1894,7 +1896,7 @@ impl<'tcx> Place<'tcx> {
|
||||||
/// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
|
/// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
|
||||||
/// same region of memory as its base.
|
/// same region of memory as its base.
|
||||||
pub fn is_indirect(&self) -> bool {
|
pub fn is_indirect(&self) -> bool {
|
||||||
self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect()))
|
self.projection.iter().any(|elem| elem.is_indirect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
|
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
|
||||||
|
|
@ -1905,61 +1907,16 @@ impl<'tcx> Place<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} |
|
} |
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(box Projection {
|
projection: box [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => Some(*local),
|
} => Some(*local),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively "iterates" over place components, generating a `PlaceBase` and
|
|
||||||
/// `Projections` list and invoking `op` with a `ProjectionsIter`.
|
|
||||||
pub fn iterate<R>(
|
|
||||||
&self,
|
|
||||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
|
||||||
) -> R {
|
|
||||||
Place::iterate_over(&self.base, &self.projection, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iterate_over<R>(
|
|
||||||
place_base: &PlaceBase<'tcx>,
|
|
||||||
place_projection: &Option<Box<Projection<'tcx>>>,
|
|
||||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
|
||||||
) -> R {
|
|
||||||
fn iterate_over2<'tcx, R>(
|
|
||||||
place_base: &PlaceBase<'tcx>,
|
|
||||||
place_projection: &Option<Box<Projection<'tcx>>>,
|
|
||||||
next: &Projections<'_, 'tcx>,
|
|
||||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
|
||||||
) -> R {
|
|
||||||
match place_projection {
|
|
||||||
None => {
|
|
||||||
op(place_base, next.iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(interior) => {
|
|
||||||
iterate_over2(
|
|
||||||
place_base,
|
|
||||||
&interior.base,
|
|
||||||
&Projections::List {
|
|
||||||
projection: interior,
|
|
||||||
next,
|
|
||||||
},
|
|
||||||
op,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iterate_over2(place_base, place_projection, &Projections::Empty, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
|
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: &self.base,
|
base: &self.base,
|
||||||
|
|
@ -1972,7 +1929,7 @@ impl From<Local> for Place<'_> {
|
||||||
fn from(local: Local) -> Self {
|
fn from(local: Local) -> Self {
|
||||||
Place {
|
Place {
|
||||||
base: local.into(),
|
base: local.into(),
|
||||||
projection: None,
|
projection: Box::new([]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1984,13 +1941,6 @@ impl From<Local> for PlaceBase<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
||||||
pub fn iterate<R>(
|
|
||||||
&self,
|
|
||||||
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
|
|
||||||
) -> R {
|
|
||||||
Place::iterate_over(self.base, self.projection, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
|
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
|
||||||
/// a single deref of a local.
|
/// a single deref of a local.
|
||||||
//
|
//
|
||||||
|
|
@ -1999,143 +1949,71 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
||||||
match self {
|
match self {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} |
|
} |
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(box Projection {
|
projection: [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => Some(*local),
|
} => Some(*local),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A linked list of projections running up the stack; begins with the
|
|
||||||
/// innermost projection and extends to the outermost (e.g., `a.b.c`
|
|
||||||
/// would have the place `b` with a "next" pointer to `b.c`).
|
|
||||||
/// Created by `Place::iterate`.
|
|
||||||
///
|
|
||||||
/// N.B., this particular impl strategy is not the most obvious. It was
|
|
||||||
/// chosen because it makes a measurable difference to NLL
|
|
||||||
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
|
|
||||||
pub enum Projections<'p, 'tcx> {
|
|
||||||
Empty,
|
|
||||||
|
|
||||||
List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'p, 'tcx> Projections<'p, 'tcx> {
|
|
||||||
fn iter(&self) -> ProjectionsIter<'_, 'tcx> {
|
|
||||||
ProjectionsIter { value: self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> {
|
|
||||||
type Item = &'p Projection<'tcx>;
|
|
||||||
type IntoIter = ProjectionsIter<'p, 'tcx>;
|
|
||||||
|
|
||||||
/// Converts a list of `Projection` components into an iterator;
|
|
||||||
/// this iterator yields up a never-ending stream of `Option<&Place>`.
|
|
||||||
/// These begin with the "innermost" projection and then with each
|
|
||||||
/// projection therefrom. So given a place like `a.b.c` it would
|
|
||||||
/// yield up:
|
|
||||||
///
|
|
||||||
/// ```notrust
|
|
||||||
/// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
|
|
||||||
/// ```
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
self.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterator over components; see `Projections::iter` for more
|
|
||||||
/// information.
|
|
||||||
///
|
|
||||||
/// N.B., this is not a *true* Rust iterator -- the code above just
|
|
||||||
/// manually invokes `next`. This is because we (sometimes) want to
|
|
||||||
/// keep executing even after `None` has been returned.
|
|
||||||
pub struct ProjectionsIter<'p, 'tcx> {
|
|
||||||
pub value: &'p Projections<'p, 'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> {
|
|
||||||
type Item = &'p Projection<'tcx>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let &Projections::List { projection, next } = self.value {
|
|
||||||
self.value = next;
|
|
||||||
Some(projection)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {}
|
|
||||||
|
|
||||||
impl Debug for Place<'_> {
|
impl Debug for Place<'_> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
self.iterate(|_place_base, place_projections| {
|
for elem in self.projection.iter().rev() {
|
||||||
// FIXME: remove this collect once we have migrated to slices
|
match elem {
|
||||||
let projs_vec: Vec<_> = place_projections.collect();
|
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
|
||||||
for projection in projs_vec.iter().rev() {
|
write!(fmt, "(").unwrap();
|
||||||
match projection.elem {
|
}
|
||||||
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
|
ProjectionElem::Deref => {
|
||||||
write!(fmt, "(").unwrap();
|
write!(fmt, "(*").unwrap();
|
||||||
}
|
}
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Index(_)
|
||||||
write!(fmt, "(*").unwrap();
|
| ProjectionElem::ConstantIndex { .. }
|
||||||
}
|
| ProjectionElem::Subslice { .. } => {}
|
||||||
ProjectionElem::Index(_)
|
}
|
||||||
| ProjectionElem::ConstantIndex { .. }
|
}
|
||||||
| ProjectionElem::Subslice { .. } => {}
|
|
||||||
|
write!(fmt, "{:?}", self.base)?;
|
||||||
|
|
||||||
|
for elem in self.projection.iter() {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Downcast(Some(name), _index) => {
|
||||||
|
write!(fmt, " as {})", name)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Downcast(None, index) => {
|
||||||
|
write!(fmt, " as variant#{:?})", index)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Deref => {
|
||||||
|
write!(fmt, ")")?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Field(field, ty) => {
|
||||||
|
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Index(ref index) => {
|
||||||
|
write!(fmt, "[{:?}]", index)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
|
||||||
|
write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
|
||||||
|
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Subslice { from, to } if *to == 0 => {
|
||||||
|
write!(fmt, "[{:?}:]", from)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Subslice { from, to } if *from == 0 => {
|
||||||
|
write!(fmt, "[:-{:?}]", to)?;
|
||||||
|
}
|
||||||
|
ProjectionElem::Subslice { from, to } => {
|
||||||
|
write!(fmt, "[{:?}:-{:?}]", from, to)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
self.iterate(|place_base, place_projections| {
|
Ok(())
|
||||||
write!(fmt, "{:?}", place_base)?;
|
|
||||||
|
|
||||||
for projection in place_projections {
|
|
||||||
match projection.elem {
|
|
||||||
ProjectionElem::Downcast(Some(name), _index) => {
|
|
||||||
write!(fmt, " as {})", name)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Downcast(None, index) => {
|
|
||||||
write!(fmt, " as variant#{:?})", index)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Deref => {
|
|
||||||
write!(fmt, ")")?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Field(field, ty) => {
|
|
||||||
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Index(ref index) => {
|
|
||||||
write!(fmt, "[{:?}]", index)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
|
|
||||||
write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
|
|
||||||
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Subslice { from, to } if to == 0 => {
|
|
||||||
write!(fmt, "[{:?}:]", from)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Subslice { from, to } if from == 0 => {
|
|
||||||
write!(fmt, "[:-{:?}]", to)?;
|
|
||||||
}
|
|
||||||
ProjectionElem::Subslice { from, to } => {
|
|
||||||
write!(fmt, "[{:?}:-{:?}]", from, to)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3120,14 +2998,14 @@ BraceStructTypeFoldableImpl! {
|
||||||
|
|
||||||
EnumTypeFoldableImpl! {
|
EnumTypeFoldableImpl! {
|
||||||
impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
|
impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
|
||||||
(StatementKind::Assign)(a, b),
|
(StatementKind::Assign)(a),
|
||||||
(StatementKind::FakeRead)(cause, place),
|
(StatementKind::FakeRead)(cause, place),
|
||||||
(StatementKind::SetDiscriminant) { place, variant_index },
|
(StatementKind::SetDiscriminant) { place, variant_index },
|
||||||
(StatementKind::StorageLive)(a),
|
(StatementKind::StorageLive)(a),
|
||||||
(StatementKind::StorageDead)(a),
|
(StatementKind::StorageDead)(a),
|
||||||
(StatementKind::InlineAsm)(a),
|
(StatementKind::InlineAsm)(a),
|
||||||
(StatementKind::Retag)(kind, place),
|
(StatementKind::Retag)(kind, place),
|
||||||
(StatementKind::AscribeUserType)(a, v, b),
|
(StatementKind::AscribeUserType)(a, v),
|
||||||
(StatementKind::Nop),
|
(StatementKind::Nop),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3409,30 +3287,26 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> {
|
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
|
||||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||||
use crate::mir::ProjectionElem::*;
|
use crate::mir::ProjectionElem::*;
|
||||||
|
|
||||||
let base = self.base.fold_with(folder);
|
match self {
|
||||||
let elem = match self.elem {
|
|
||||||
Deref => Deref,
|
Deref => Deref,
|
||||||
Field(f, ref ty) => Field(f, ty.fold_with(folder)),
|
Field(f, ty) => Field(*f, ty.fold_with(folder)),
|
||||||
Index(ref v) => Index(v.fold_with(folder)),
|
Index(v) => Index(v.fold_with(folder)),
|
||||||
ref elem => elem.clone(),
|
elem => elem.clone(),
|
||||||
};
|
}
|
||||||
|
|
||||||
Projection { base, elem }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
|
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
|
||||||
use crate::mir::ProjectionElem::*;
|
use crate::mir::ProjectionElem::*;
|
||||||
|
|
||||||
self.base.visit_with(visitor)
|
match self {
|
||||||
|| match self.elem {
|
Field(_, ty) => ty.visit_with(visitor),
|
||||||
Field(_, ref ty) => ty.visit_with(visitor),
|
Index(v) => v.visit_with(visitor),
|
||||||
Index(ref v) => v.visit_with(visitor),
|
_ => false,
|
||||||
_ => false,
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,21 +121,16 @@ BraceStructTypeFoldableImpl! {
|
||||||
impl<'tcx> Place<'tcx> {
|
impl<'tcx> Place<'tcx> {
|
||||||
pub fn ty_from<D>(
|
pub fn ty_from<D>(
|
||||||
base: &PlaceBase<'tcx>,
|
base: &PlaceBase<'tcx>,
|
||||||
projection: &Option<Box<Projection<'tcx>>>,
|
projection: &[PlaceElem<'tcx>],
|
||||||
local_decls: &D,
|
local_decls: &D,
|
||||||
tcx: TyCtxt<'tcx>
|
tcx: TyCtxt<'tcx>
|
||||||
) -> PlaceTy<'tcx>
|
) -> PlaceTy<'tcx>
|
||||||
where D: HasLocalDecls<'tcx>
|
where D: HasLocalDecls<'tcx>
|
||||||
{
|
{
|
||||||
Place::iterate_over(base, projection, |place_base, place_projections| {
|
projection.iter().fold(
|
||||||
let mut place_ty = place_base.ty(local_decls);
|
base.ty(local_decls),
|
||||||
|
|place_ty, elem| place_ty.projection_ty(tcx, elem)
|
||||||
for proj in place_projections {
|
)
|
||||||
place_ty = place_ty.projection_ty(tcx, &proj.elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
place_ty
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
|
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
|
||||||
|
|
|
||||||
|
|
@ -152,18 +152,18 @@ macro_rules! make_mir_visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_place_base(&mut self,
|
fn visit_place_base(&mut self,
|
||||||
place_base: & $($mutability)? PlaceBase<'tcx>,
|
base: & $($mutability)? PlaceBase<'tcx>,
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
self.super_place_base(place_base, context, location);
|
self.super_place_base(base, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_projection(&mut self,
|
fn visit_projection(&mut self,
|
||||||
place_base: & $($mutability)? PlaceBase<'tcx>,
|
base: & $($mutability)? PlaceBase<'tcx>,
|
||||||
place: & $($mutability)? Projection<'tcx>,
|
projection: & $($mutability)? [PlaceElem<'tcx>],
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
self.super_projection(place_base, place, context, location);
|
self.super_projection(base, projection, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_constant(&mut self,
|
fn visit_constant(&mut self,
|
||||||
|
|
@ -344,7 +344,9 @@ macro_rules! make_mir_visitor {
|
||||||
|
|
||||||
self.visit_source_info(source_info);
|
self.visit_source_info(source_info);
|
||||||
match kind {
|
match kind {
|
||||||
StatementKind::Assign(place, rvalue) => {
|
StatementKind::Assign(
|
||||||
|
box(ref $($mutability)? place, ref $($mutability)? rvalue)
|
||||||
|
) => {
|
||||||
self.visit_assign(place, rvalue, location);
|
self.visit_assign(place, rvalue, location);
|
||||||
}
|
}
|
||||||
StatementKind::FakeRead(_, place) => {
|
StatementKind::FakeRead(_, place) => {
|
||||||
|
|
@ -391,7 +393,10 @@ macro_rules! make_mir_visitor {
|
||||||
StatementKind::Retag(kind, place) => {
|
StatementKind::Retag(kind, place) => {
|
||||||
self.visit_retag(kind, place, location);
|
self.visit_retag(kind, place, location);
|
||||||
}
|
}
|
||||||
StatementKind::AscribeUserType(place, variance, user_ty) => {
|
StatementKind::AscribeUserType(
|
||||||
|
box(ref $($mutability)? place, ref $($mutability)? user_ty),
|
||||||
|
variance
|
||||||
|
) => {
|
||||||
self.visit_ascribe_user_ty(place, variance, user_ty, location);
|
self.visit_ascribe_user_ty(place, variance, user_ty, location);
|
||||||
}
|
}
|
||||||
StatementKind::Nop => {}
|
StatementKind::Nop => {}
|
||||||
|
|
@ -685,7 +690,7 @@ macro_rules! make_mir_visitor {
|
||||||
location: Location) {
|
location: Location) {
|
||||||
let mut context = context;
|
let mut context = context;
|
||||||
|
|
||||||
if place.projection.is_some() {
|
if !place.projection.is_empty() {
|
||||||
context = if context.is_mutating_use() {
|
context = if context.is_mutating_use() {
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -695,9 +700,10 @@ macro_rules! make_mir_visitor {
|
||||||
|
|
||||||
self.visit_place_base(& $($mutability)? place.base, context, location);
|
self.visit_place_base(& $($mutability)? place.base, context, location);
|
||||||
|
|
||||||
if let Some(box proj) = & $($mutability)? place.projection {
|
self.visit_projection(& $($mutability)? place.base,
|
||||||
self.visit_projection(& $($mutability)? place.base, proj, context, location);
|
& $($mutability)? place.projection,
|
||||||
}
|
context,
|
||||||
|
location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_place_base(&mut self,
|
fn super_place_base(&mut self,
|
||||||
|
|
@ -715,31 +721,31 @@ macro_rules! make_mir_visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_projection(&mut self,
|
fn super_projection(&mut self,
|
||||||
place_base: & $($mutability)? PlaceBase<'tcx>,
|
base: & $($mutability)? PlaceBase<'tcx>,
|
||||||
proj: & $($mutability)? Projection<'tcx>,
|
projection: & $($mutability)? [PlaceElem<'tcx>],
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Some(box proj_base) = & $($mutability)? proj.base {
|
if let [proj_base @ .., elem] = projection {
|
||||||
self.visit_projection(place_base, proj_base, context, location);
|
self.visit_projection(base, proj_base, context, location);
|
||||||
}
|
|
||||||
|
|
||||||
match & $($mutability)? proj.elem {
|
match elem {
|
||||||
ProjectionElem::Field(_field, ty) => {
|
ProjectionElem::Field(_field, ty) => {
|
||||||
self.visit_ty(ty, TyContext::Location(location));
|
self.visit_ty(ty, TyContext::Location(location));
|
||||||
}
|
}
|
||||||
ProjectionElem::Index(local) => {
|
ProjectionElem::Index(local) => {
|
||||||
self.visit_local(
|
self.visit_local(
|
||||||
local,
|
local,
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||||
location
|
location
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ProjectionElem::Deref |
|
ProjectionElem::Deref |
|
||||||
ProjectionElem::Subslice { from: _, to: _ } |
|
ProjectionElem::Subslice { from: _, to: _ } |
|
||||||
ProjectionElem::ConstantIndex { offset: _,
|
ProjectionElem::ConstantIndex { offset: _,
|
||||||
min_length: _,
|
min_length: _,
|
||||||
from_end: _ } |
|
from_end: _ } |
|
||||||
ProjectionElem::Downcast(_, _) => {
|
ProjectionElem::Downcast(_, _) => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(libc)]
|
#![feature(libc)]
|
||||||
|
#![feature(slice_patterns)]
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
#![feature(in_band_lifetimes)]
|
#![feature(in_band_lifetimes)]
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
) {
|
) {
|
||||||
let cx = self.fx.cx;
|
let cx = self.fx.cx;
|
||||||
|
|
||||||
if let Some(proj) = place_ref.projection {
|
if let [proj_base @ .., elem] = place_ref.projection {
|
||||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||||
let is_consume = match context {
|
let is_consume = match context {
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||||
|
|
@ -114,12 +114,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
};
|
};
|
||||||
if is_consume {
|
if is_consume {
|
||||||
let base_ty =
|
let base_ty =
|
||||||
mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx());
|
mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx());
|
||||||
let base_ty = self.fx.monomorphize(&base_ty);
|
let base_ty = self.fx.monomorphize(&base_ty);
|
||||||
|
|
||||||
// ZSTs don't require any actual memory access.
|
// ZSTs don't require any actual memory access.
|
||||||
let elem_ty = base_ty
|
let elem_ty = base_ty
|
||||||
.projection_ty(cx.tcx(), &proj.elem)
|
.projection_ty(cx.tcx(), elem)
|
||||||
.ty;
|
.ty;
|
||||||
let elem_ty = self.fx.monomorphize(&elem_ty);
|
let elem_ty = self.fx.monomorphize(&elem_ty);
|
||||||
let span = if let mir::PlaceBase::Local(index) = place_ref.base {
|
let span = if let mir::PlaceBase::Local(index) = place_ref.base {
|
||||||
|
|
@ -131,7 +131,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let mir::ProjectionElem::Field(..) = proj.elem {
|
if let mir::ProjectionElem::Field(..) = elem {
|
||||||
let layout = cx.spanned_layout_of(base_ty.ty, span);
|
let layout = cx.spanned_layout_of(base_ty.ty, span);
|
||||||
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
|
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
|
||||||
// Recurse with the same context, instead of `Projection`,
|
// Recurse with the same context, instead of `Projection`,
|
||||||
|
|
@ -140,7 +140,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
self.process_place(
|
self.process_place(
|
||||||
&mir::PlaceRef {
|
&mir::PlaceRef {
|
||||||
base: place_ref.base,
|
base: place_ref.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
location,
|
location,
|
||||||
|
|
@ -151,11 +151,11 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A deref projection only reads the pointer, never needs the place.
|
// A deref projection only reads the pointer, never needs the place.
|
||||||
if let mir::ProjectionElem::Deref = proj.elem {
|
if let mir::ProjectionElem::Deref = elem {
|
||||||
self.process_place(
|
self.process_place(
|
||||||
&mir::PlaceRef {
|
&mir::PlaceRef {
|
||||||
base: place_ref.base,
|
base: place_ref.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||||
location
|
location
|
||||||
|
|
@ -168,7 +168,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
// visit_place API
|
// visit_place API
|
||||||
let mut context = context;
|
let mut context = context;
|
||||||
|
|
||||||
if place_ref.projection.is_some() {
|
if !place_ref.projection.is_empty() {
|
||||||
context = if context.is_mutating_use() {
|
context = if context.is_mutating_use() {
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -177,10 +177,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_place_base(place_ref.base, context, location);
|
self.visit_place_base(place_ref.base, context, location);
|
||||||
|
self.visit_projection(place_ref.base, place_ref.projection, context, location);
|
||||||
if let Some(box proj) = place_ref.projection {
|
|
||||||
self.visit_projection(place_ref.base, proj, context, location);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +193,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
||||||
|
|
||||||
if let mir::Place {
|
if let mir::Place {
|
||||||
base: mir::PlaceBase::Local(index),
|
base: mir::PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *place {
|
} = *place {
|
||||||
self.assign(index, location);
|
self.assign(index, location);
|
||||||
let decl_span = self.fx.mir.local_decls[index].source_info.span;
|
let decl_span = self.fx.mir.local_decls[index].source_info.span;
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
|
|
||||||
PassMode::Direct(_) | PassMode::Pair(..) => {
|
PassMode::Direct(_) | PassMode::Pair(..) => {
|
||||||
let op =
|
let op =
|
||||||
self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_ref());
|
self.codegen_consume(&mut bx, &mir::Place::return_place().as_ref());
|
||||||
if let Ref(llval, _, align) = op.val {
|
if let Ref(llval, _, align) = op.val {
|
||||||
bx.load(llval, align)
|
bx.load(llval, align)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -612,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
ty,
|
ty,
|
||||||
def_id: _,
|
def_id: _,
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}
|
}
|
||||||
) |
|
) |
|
||||||
mir::Operand::Move(
|
mir::Operand::Move(
|
||||||
|
|
@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
ty,
|
ty,
|
||||||
def_id: _,
|
def_id: _,
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
|
|
@ -1105,7 +1105,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
let dest = if let mir::Place {
|
let dest = if let mir::Place {
|
||||||
base: mir::PlaceBase::Local(index),
|
base: mir::PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *dest {
|
} = *dest {
|
||||||
match self.locals[index] {
|
match self.locals[index] {
|
||||||
LocalRef::Place(dest) => dest,
|
LocalRef::Place(dest) => dest,
|
||||||
|
|
@ -1166,7 +1166,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
) {
|
) {
|
||||||
if let mir::Place {
|
if let mir::Place {
|
||||||
base: mir::PlaceBase::Local(index),
|
base: mir::PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *dst {
|
} = *dst {
|
||||||
match self.locals[index] {
|
match self.locals[index] {
|
||||||
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
||||||
|
|
|
||||||
|
|
@ -384,47 +384,45 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
) -> Option<OperandRef<'tcx, Bx::Value>> {
|
) -> Option<OperandRef<'tcx, Bx::Value>> {
|
||||||
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
|
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
|
||||||
|
|
||||||
place_ref.iterate(|place_base, place_projection| {
|
if let mir::PlaceBase::Local(index) = place_ref.base {
|
||||||
if let mir::PlaceBase::Local(index) = place_base {
|
match self.locals[*index] {
|
||||||
match self.locals[*index] {
|
LocalRef::Operand(Some(mut o)) => {
|
||||||
LocalRef::Operand(Some(mut o)) => {
|
// Moves out of scalar and scalar pair fields are trivial.
|
||||||
// Moves out of scalar and scalar pair fields are trivial.
|
for elem in place_ref.projection.iter() {
|
||||||
for proj in place_projection {
|
match elem {
|
||||||
match proj.elem {
|
mir::ProjectionElem::Field(ref f, _) => {
|
||||||
mir::ProjectionElem::Field(ref f, _) => {
|
o = o.extract_field(bx, f.index());
|
||||||
o = o.extract_field(bx, f.index());
|
|
||||||
}
|
|
||||||
mir::ProjectionElem::Index(_) |
|
|
||||||
mir::ProjectionElem::ConstantIndex { .. } => {
|
|
||||||
// ZSTs don't require any actual memory access.
|
|
||||||
// FIXME(eddyb) deduplicate this with the identical
|
|
||||||
// checks in `codegen_consume` and `extract_field`.
|
|
||||||
let elem = o.layout.field(bx.cx(), 0);
|
|
||||||
if elem.is_zst() {
|
|
||||||
o = OperandRef::new_zst(bx, elem);
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return None,
|
|
||||||
}
|
}
|
||||||
|
mir::ProjectionElem::Index(_) |
|
||||||
|
mir::ProjectionElem::ConstantIndex { .. } => {
|
||||||
|
// ZSTs don't require any actual memory access.
|
||||||
|
// FIXME(eddyb) deduplicate this with the identical
|
||||||
|
// checks in `codegen_consume` and `extract_field`.
|
||||||
|
let elem = o.layout.field(bx.cx(), 0);
|
||||||
|
if elem.is_zst() {
|
||||||
|
o = OperandRef::new_zst(bx, elem);
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some(o)
|
Some(o)
|
||||||
}
|
}
|
||||||
LocalRef::Operand(None) => {
|
LocalRef::Operand(None) => {
|
||||||
bug!("use of {:?} before def", place_ref);
|
bug!("use of {:?} before def", place_ref);
|
||||||
}
|
}
|
||||||
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
|
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
|
||||||
// watch out for locals that do not have an
|
// watch out for locals that do not have an
|
||||||
// alloca; they are handled somewhat differently
|
// alloca; they are handled somewhat differently
|
||||||
None
|
None
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn codegen_consume(
|
pub fn codegen_consume(
|
||||||
|
|
|
||||||
|
|
@ -449,7 +449,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let result = match &place_ref {
|
let result = match &place_ref {
|
||||||
mir::PlaceRef {
|
mir::PlaceRef {
|
||||||
base: mir::PlaceBase::Local(index),
|
base: mir::PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
match self.locals[*index] {
|
match self.locals[*index] {
|
||||||
LocalRef::Place(place) => {
|
LocalRef::Place(place) => {
|
||||||
|
|
@ -469,7 +469,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
kind: mir::StaticKind::Promoted(promoted, substs),
|
kind: mir::StaticKind::Promoted(promoted, substs),
|
||||||
def_id,
|
def_id,
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
let instance = Instance::new(*def_id, self.monomorphize(substs));
|
let instance = Instance::new(*def_id, self.monomorphize(substs));
|
||||||
|
|
@ -504,7 +504,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
kind: mir::StaticKind::Static,
|
kind: mir::StaticKind::Static,
|
||||||
def_id,
|
def_id,
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
// NB: The layout of a static may be unsized as is the case when working
|
// NB: The layout of a static may be unsized as is the case when working
|
||||||
// with a static that is an extern_type.
|
// with a static that is an extern_type.
|
||||||
|
|
@ -514,10 +514,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
},
|
},
|
||||||
mir::PlaceRef {
|
mir::PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(box mir::Projection {
|
projection: [proj_base @ .., mir::ProjectionElem::Deref],
|
||||||
base: proj_base,
|
|
||||||
elem: mir::ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
// Load the pointer from its location.
|
// Load the pointer from its location.
|
||||||
self.codegen_consume(bx, &mir::PlaceRef {
|
self.codegen_consume(bx, &mir::PlaceRef {
|
||||||
|
|
@ -527,22 +524,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
mir::PlaceRef {
|
mir::PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(projection),
|
projection: [proj_base @ .., elem],
|
||||||
} => {
|
} => {
|
||||||
// FIXME turn this recursion into iteration
|
// FIXME turn this recursion into iteration
|
||||||
let cg_base = self.codegen_place(bx, &mir::PlaceRef {
|
let cg_base = self.codegen_place(bx, &mir::PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &projection.base,
|
projection: proj_base,
|
||||||
});
|
});
|
||||||
|
|
||||||
match projection.elem {
|
match elem {
|
||||||
mir::ProjectionElem::Deref => bug!(),
|
mir::ProjectionElem::Deref => bug!(),
|
||||||
mir::ProjectionElem::Field(ref field, _) => {
|
mir::ProjectionElem::Field(ref field, _) => {
|
||||||
cg_base.project_field(bx, field.index())
|
cg_base.project_field(bx, field.index())
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Index(index) => {
|
mir::ProjectionElem::Index(index) => {
|
||||||
let index = &mir::Operand::Copy(
|
let index = &mir::Operand::Copy(
|
||||||
mir::Place::from(index)
|
mir::Place::from(*index)
|
||||||
);
|
);
|
||||||
let index = self.codegen_operand(bx, index);
|
let index = self.codegen_operand(bx, index);
|
||||||
let llindex = index.immediate();
|
let llindex = index.immediate();
|
||||||
|
|
@ -551,27 +548,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
mir::ProjectionElem::ConstantIndex { offset,
|
mir::ProjectionElem::ConstantIndex { offset,
|
||||||
from_end: false,
|
from_end: false,
|
||||||
min_length: _ } => {
|
min_length: _ } => {
|
||||||
let lloffset = bx.cx().const_usize(offset as u64);
|
let lloffset = bx.cx().const_usize(*offset as u64);
|
||||||
cg_base.project_index(bx, lloffset)
|
cg_base.project_index(bx, lloffset)
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::ConstantIndex { offset,
|
mir::ProjectionElem::ConstantIndex { offset,
|
||||||
from_end: true,
|
from_end: true,
|
||||||
min_length: _ } => {
|
min_length: _ } => {
|
||||||
let lloffset = bx.cx().const_usize(offset as u64);
|
let lloffset = bx.cx().const_usize(*offset as u64);
|
||||||
let lllen = cg_base.len(bx.cx());
|
let lllen = cg_base.len(bx.cx());
|
||||||
let llindex = bx.sub(lllen, lloffset);
|
let llindex = bx.sub(lllen, lloffset);
|
||||||
cg_base.project_index(bx, llindex)
|
cg_base.project_index(bx, llindex)
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Subslice { from, to } => {
|
mir::ProjectionElem::Subslice { from, to } => {
|
||||||
let mut subslice = cg_base.project_index(bx,
|
let mut subslice = cg_base.project_index(bx,
|
||||||
bx.cx().const_usize(from as u64));
|
bx.cx().const_usize(*from as u64));
|
||||||
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
|
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
|
||||||
.projection_ty(tcx, &projection.elem).ty;
|
.projection_ty(tcx, elem).ty;
|
||||||
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
|
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
|
||||||
|
|
||||||
if subslice.layout.is_unsized() {
|
if subslice.layout.is_unsized() {
|
||||||
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
|
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
|
||||||
bx.cx().const_usize((from as u64) + (to as u64))));
|
bx.cx().const_usize((*from as u64) + (*to as u64))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast the place pointer type to the new
|
// Cast the place pointer type to the new
|
||||||
|
|
@ -582,7 +579,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
subslice
|
subslice
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Downcast(_, v) => {
|
mir::ProjectionElem::Downcast(_, v) => {
|
||||||
cg_base.project_downcast(bx, v)
|
cg_base.project_downcast(bx, *v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -522,7 +522,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
// because codegen_place() panics if Local is operand.
|
// because codegen_place() panics if Local is operand.
|
||||||
if let mir::Place {
|
if let mir::Place {
|
||||||
base: mir::PlaceBase::Local(index),
|
base: mir::PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *place {
|
} = *place {
|
||||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||||
if let ty::Array(_, n) = op.layout.ty.sty {
|
if let ty::Array(_, n) = op.layout.ty.sty {
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
|
|
||||||
self.set_debug_loc(&mut bx, statement.source_info);
|
self.set_debug_loc(&mut bx, statement.source_info);
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
mir::StatementKind::Assign(ref place, ref rvalue) => {
|
mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
|
||||||
if let mir::Place {
|
if let mir::Place {
|
||||||
base: mir::PlaceBase::Local(index),
|
base: mir::PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *place {
|
} = place {
|
||||||
match self.locals[index] {
|
match self.locals[*index] {
|
||||||
LocalRef::Place(cg_dest) => {
|
LocalRef::Place(cg_dest) => {
|
||||||
self.codegen_rvalue(bx, cg_dest, rvalue)
|
self.codegen_rvalue(bx, cg_dest, rvalue)
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
LocalRef::Operand(None) => {
|
LocalRef::Operand(None) => {
|
||||||
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
|
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
|
||||||
if let Some(name) = self.mir.local_decls[index].name {
|
if let Some(name) = self.mir.local_decls[*index].name {
|
||||||
match operand.val {
|
match operand.val {
|
||||||
OperandValue::Ref(x, ..) |
|
OperandValue::Ref(x, ..) |
|
||||||
OperandValue::Immediate(x) => {
|
OperandValue::Immediate(x) => {
|
||||||
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.locals[index] = LocalRef::Operand(Some(operand));
|
self.locals[*index] = LocalRef::Operand(Some(operand));
|
||||||
bx
|
bx
|
||||||
}
|
}
|
||||||
LocalRef::Operand(Some(op)) => {
|
LocalRef::Operand(Some(op)) => {
|
||||||
|
|
@ -64,7 +64,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
self.codegen_rvalue(bx, cg_dest, rvalue)
|
self.codegen_rvalue(bx, cg_dest, rvalue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::StatementKind::SetDiscriminant{ref place, variant_index} => {
|
mir::StatementKind::SetDiscriminant{box ref place, variant_index} => {
|
||||||
self.codegen_place(&mut bx, &place.as_ref())
|
self.codegen_place(&mut bx, &place.as_ref())
|
||||||
.codegen_set_discr(&mut bx, variant_index);
|
.codegen_set_discr(&mut bx, variant_index);
|
||||||
bx
|
bx
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
||||||
// so extract `temp`.
|
// so extract `temp`.
|
||||||
let temp = if let &mir::Place {
|
let temp = if let &mir::Place {
|
||||||
base: mir::PlaceBase::Local(temp),
|
base: mir::PlaceBase::Local(temp),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = assigned_place {
|
} = assigned_place {
|
||||||
temp
|
temp
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
|
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
|
||||||
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef,
|
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
|
||||||
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
|
Statement, StatementKind, TerminatorKind, VarBindingForm,
|
||||||
};
|
};
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
|
@ -244,7 +244,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
let span = if let Place {
|
let span = if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = place {
|
} = place {
|
||||||
let decl = &self.body.local_decls[*local];
|
let decl = &self.body.local_decls[*local];
|
||||||
Some(decl.source_info.span)
|
Some(decl.source_info.span)
|
||||||
|
|
@ -614,17 +614,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
projection,
|
projection,
|
||||||
} = first_borrowed_place;
|
} = first_borrowed_place;
|
||||||
|
|
||||||
let mut current = projection;
|
for (i, elem) in projection.iter().enumerate().rev() {
|
||||||
|
let proj_base = &projection[..i];
|
||||||
|
|
||||||
while let Some(box Projection { base: base_proj, elem }) = current {
|
|
||||||
match elem {
|
match elem {
|
||||||
ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => {
|
ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
|
||||||
return Some((PlaceRef {
|
return Some((PlaceRef {
|
||||||
base: base,
|
base: base,
|
||||||
projection: base_proj,
|
projection: proj_base,
|
||||||
}, field));
|
}, field));
|
||||||
},
|
},
|
||||||
_ => current = base_proj,
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
@ -637,9 +637,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
projection,
|
projection,
|
||||||
} = second_borrowed_place;
|
} = second_borrowed_place;
|
||||||
|
|
||||||
let mut current = projection;
|
for (i, elem) in projection.iter().enumerate().rev() {
|
||||||
|
let proj_base = &projection[..i];
|
||||||
|
|
||||||
while let Some(box Projection { base: proj_base, elem }) = current {
|
|
||||||
if let ProjectionElem::Field(field, _) = elem {
|
if let ProjectionElem::Field(field, _) = elem {
|
||||||
if let Some(union_ty) = union_ty(base, proj_base) {
|
if let Some(union_ty) = union_ty(base, proj_base) {
|
||||||
if field != target_field
|
if field != target_field
|
||||||
|
|
@ -660,8 +660,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current = proj_base;
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
|
|
@ -707,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||||
let borrow_span = borrow_spans.var_or_use();
|
let borrow_span = borrow_spans.var_or_use();
|
||||||
|
|
||||||
assert!(root_place.projection.is_none());
|
assert!(root_place.projection.is_empty());
|
||||||
let proper_span = match root_place.base {
|
let proper_span = match root_place.base {
|
||||||
PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
|
PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
|
||||||
_ => drop_span,
|
_ => drop_span,
|
||||||
|
|
@ -716,7 +714,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if self.access_place_error_reported
|
if self.access_place_error_reported
|
||||||
.contains(&(Place {
|
.contains(&(Place {
|
||||||
base: root_place.base.clone(),
|
base: root_place.base.clone(),
|
||||||
projection: root_place.projection.clone(),
|
projection: root_place.projection.to_vec().into_boxed_slice(),
|
||||||
}, borrow_span))
|
}, borrow_span))
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
|
|
@ -729,7 +727,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.access_place_error_reported
|
self.access_place_error_reported
|
||||||
.insert((Place {
|
.insert((Place {
|
||||||
base: root_place.base.clone(),
|
base: root_place.base.clone(),
|
||||||
projection: root_place.projection.clone(),
|
projection: root_place.projection.to_vec().into_boxed_slice(),
|
||||||
}, borrow_span));
|
}, borrow_span));
|
||||||
|
|
||||||
if let StorageDeadOrDrop::Destructor(dropped_ty) =
|
if let StorageDeadOrDrop::Destructor(dropped_ty) =
|
||||||
|
|
@ -1107,7 +1105,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let local_kind = match borrow.borrowed_place {
|
let local_kind = match borrow.borrowed_place {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} => {
|
} => {
|
||||||
match self.body.local_kind(local) {
|
match self.body.local_kind(local) {
|
||||||
LocalKind::ReturnPointer
|
LocalKind::ReturnPointer
|
||||||
|
|
@ -1136,7 +1134,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let local = if let PlaceRef {
|
let local = if let PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} = root_place {
|
} = root_place {
|
||||||
local
|
local
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1446,7 +1444,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
) {
|
) {
|
||||||
let (from_arg, local_decl) = if let Place {
|
let (from_arg, local_decl) = if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *err_place {
|
} = *err_place {
|
||||||
if let LocalKind::Arg = self.body.local_kind(local) {
|
if let LocalKind::Arg = self.body.local_kind(local) {
|
||||||
(true, Some(&self.body.local_decls[local]))
|
(true, Some(&self.body.local_decls[local]))
|
||||||
|
|
@ -1519,20 +1517,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
|
fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
match place.projection {
|
match place.projection {
|
||||||
None => {
|
[] => {
|
||||||
StorageDeadOrDrop::LocalStorageDead
|
StorageDeadOrDrop::LocalStorageDead
|
||||||
}
|
}
|
||||||
Some(box Projection { ref base, ref elem }) => {
|
[proj_base @ .., elem] => {
|
||||||
|
// FIXME(spastorino) make this iterate
|
||||||
let base_access = self.classify_drop_access_kind(PlaceRef {
|
let base_access = self.classify_drop_access_kind(PlaceRef {
|
||||||
base: place.base,
|
base: place.base,
|
||||||
projection: base,
|
projection: proj_base,
|
||||||
});
|
});
|
||||||
match elem {
|
match elem {
|
||||||
ProjectionElem::Deref => match base_access {
|
ProjectionElem::Deref => match base_access {
|
||||||
StorageDeadOrDrop::LocalStorageDead
|
StorageDeadOrDrop::LocalStorageDead
|
||||||
| StorageDeadOrDrop::BoxedStorageDead => {
|
| StorageDeadOrDrop::BoxedStorageDead => {
|
||||||
assert!(
|
assert!(
|
||||||
Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(),
|
Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(),
|
||||||
"Drop of value behind a reference or raw pointer"
|
"Drop of value behind a reference or raw pointer"
|
||||||
);
|
);
|
||||||
StorageDeadOrDrop::BoxedStorageDead
|
StorageDeadOrDrop::BoxedStorageDead
|
||||||
|
|
@ -1540,7 +1539,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
StorageDeadOrDrop::Destructor(_) => base_access,
|
StorageDeadOrDrop::Destructor(_) => base_access,
|
||||||
},
|
},
|
||||||
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
|
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
|
||||||
let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
|
let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
|
||||||
match base_ty.sty {
|
match base_ty.sty {
|
||||||
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
||||||
// Report the outermost adt with a destructor
|
// Report the outermost adt with a destructor
|
||||||
|
|
@ -1598,7 +1597,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
"annotate_argument_and_return_for_borrow: location={:?}",
|
"annotate_argument_and_return_for_borrow: location={:?}",
|
||||||
location
|
location
|
||||||
);
|
);
|
||||||
if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
|
if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
|
||||||
= &self.body[location.block].statements.get(location.statement_index)
|
= &self.body[location.block].statements.get(location.statement_index)
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
|
|
@ -1609,7 +1608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let mut target = *match reservation {
|
let mut target = *match reservation {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} if self.body.local_kind(*local) == LocalKind::Temp => local,
|
} if self.body.local_kind(*local) == LocalKind::Temp => local,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
@ -1623,11 +1622,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
target, stmt
|
target, stmt
|
||||||
);
|
);
|
||||||
if let StatementKind::Assign(
|
if let StatementKind::Assign(
|
||||||
Place {
|
box(
|
||||||
base: PlaceBase::Local(assigned_to),
|
Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(assigned_to),
|
||||||
},
|
projection: box [],
|
||||||
box rvalue
|
},
|
||||||
|
rvalue
|
||||||
|
)
|
||||||
) = &stmt.kind {
|
) = &stmt.kind {
|
||||||
debug!(
|
debug!(
|
||||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||||
|
|
@ -1753,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if let TerminatorKind::Call {
|
if let TerminatorKind::Call {
|
||||||
destination: Some((Place {
|
destination: Some((Place {
|
||||||
base: PlaceBase::Local(assigned_to),
|
base: PlaceBase::Local(assigned_to),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, _)),
|
}, _)),
|
||||||
args,
|
args,
|
||||||
..
|
..
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let mut target = place.local_or_deref_local();
|
let mut target = place.local_or_deref_local();
|
||||||
for stmt in &self.body[location.block].statements[location.statement_index..] {
|
for stmt in &self.body[location.block].statements[location.statement_index..] {
|
||||||
debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
|
debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
|
||||||
if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind {
|
if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
|
||||||
debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
|
debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
|
||||||
match from {
|
match from {
|
||||||
Operand::Copy(ref place) |
|
Operand::Copy(ref place) |
|
||||||
|
|
@ -152,7 +152,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
match place {
|
match place {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
self.append_local_to_string(*local, buf)?;
|
self.append_local_to_string(*local, buf)?;
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
kind: StaticKind::Promoted(..),
|
kind: StaticKind::Promoted(..),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
buf.push_str("promoted");
|
buf.push_str("promoted");
|
||||||
}
|
}
|
||||||
|
|
@ -173,15 +173,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
def_id,
|
def_id,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
|
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
|
||||||
}
|
}
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(ref proj),
|
projection: [proj_base @ .., elem],
|
||||||
} => {
|
} => {
|
||||||
match proj.elem {
|
match elem {
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Deref => {
|
||||||
let upvar_field_projection =
|
let upvar_field_projection =
|
||||||
self.is_upvar_field_projection(place);
|
self.is_upvar_field_projection(place);
|
||||||
|
|
@ -199,20 +199,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
&including_downcast,
|
&including_downcast,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
match (&proj.base, base) {
|
match (proj_base, base) {
|
||||||
(None, PlaceBase::Local(local)) => {
|
([], PlaceBase::Local(local)) => {
|
||||||
if self.body.local_decls[*local].is_ref_for_guard() {
|
if self.body.local_decls[*local].is_ref_for_guard() {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
|
|
@ -224,7 +224,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
|
|
@ -238,7 +238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
|
|
@ -253,7 +253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
|
|
@ -275,12 +275,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
let field_name = self.describe_field(PlaceRef {
|
let field_name = self.describe_field(PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
}, field);
|
}, *field);
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
|
|
@ -295,14 +295,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
&including_downcast,
|
&including_downcast,
|
||||||
)?;
|
)?;
|
||||||
buf.push_str("[");
|
buf.push_str("[");
|
||||||
if self.append_local_to_string(index, buf).is_err() {
|
if self.append_local_to_string(*index, buf).is_err() {
|
||||||
buf.push_str("_");
|
buf.push_str("_");
|
||||||
}
|
}
|
||||||
buf.push_str("]");
|
buf.push_str("]");
|
||||||
|
|
@ -315,7 +315,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.append_place_to_string(
|
self.append_place_to_string(
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
},
|
},
|
||||||
buf,
|
buf,
|
||||||
autoderef,
|
autoderef,
|
||||||
|
|
@ -349,28 +349,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
match place {
|
match place {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
let local = &self.body.local_decls[*local];
|
let local = &self.body.local_decls[*local];
|
||||||
self.describe_field_from_ty(&local.ty, field, None)
|
self.describe_field_from_ty(&local.ty, field, None)
|
||||||
}
|
}
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Static(static_),
|
base: PlaceBase::Static(static_),
|
||||||
projection: None,
|
projection: [],
|
||||||
} =>
|
} =>
|
||||||
self.describe_field_from_ty(&static_.ty, field, None),
|
self.describe_field_from_ty(&static_.ty, field, None),
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(proj),
|
projection: [proj_base @ .., elem],
|
||||||
} => match proj.elem {
|
} => match elem {
|
||||||
ProjectionElem::Deref => self.describe_field(PlaceRef {
|
ProjectionElem::Deref => {
|
||||||
base,
|
self.describe_field(PlaceRef {
|
||||||
projection: &proj.base,
|
base,
|
||||||
}, field),
|
projection: proj_base,
|
||||||
|
}, field)
|
||||||
|
}
|
||||||
ProjectionElem::Downcast(_, variant_index) => {
|
ProjectionElem::Downcast(_, variant_index) => {
|
||||||
let base_ty =
|
let base_ty =
|
||||||
Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty;
|
Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty;
|
||||||
self.describe_field_from_ty(&base_ty, field, Some(variant_index))
|
self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
|
||||||
}
|
}
|
||||||
ProjectionElem::Field(_, field_type) => {
|
ProjectionElem::Field(_, field_type) => {
|
||||||
self.describe_field_from_ty(&field_type, field, None)
|
self.describe_field_from_ty(&field_type, field, None)
|
||||||
|
|
@ -380,7 +382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
| ProjectionElem::Subslice { .. } => {
|
| ProjectionElem::Subslice { .. } => {
|
||||||
self.describe_field(PlaceRef {
|
self.describe_field(PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
}, field)
|
}, field)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -445,7 +447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
def_id,
|
def_id,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} = place_ref {
|
} = place_ref {
|
||||||
let attrs = self.infcx.tcx.get_attrs(*def_id);
|
let attrs = self.infcx.tcx.get_attrs(*def_id);
|
||||||
let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
|
let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
|
||||||
|
|
@ -790,8 +792,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
||||||
if let StatementKind::Assign(
|
if let StatementKind::Assign(
|
||||||
_,
|
box(_, Rvalue::Aggregate(ref kind, ref places))
|
||||||
box Rvalue::Aggregate(ref kind, ref places)
|
|
||||||
) = stmt.kind {
|
) = stmt.kind {
|
||||||
let (def_id, is_generator) = match kind {
|
let (def_id, is_generator) = match kind {
|
||||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||||
|
|
@ -828,10 +829,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
.get(location.statement_index)
|
.get(location.statement_index)
|
||||||
{
|
{
|
||||||
Some(&Statement {
|
Some(&Statement {
|
||||||
kind: StatementKind::Assign(Place {
|
kind: StatementKind::Assign(box(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, _),
|
}, _)),
|
||||||
..
|
..
|
||||||
}) => local,
|
}) => local,
|
||||||
_ => return OtherUse(use_span),
|
_ => return OtherUse(use_span),
|
||||||
|
|
@ -844,7 +845,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
|
for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
|
||||||
if let StatementKind::Assign(
|
if let StatementKind::Assign(
|
||||||
_, box Rvalue::Aggregate(ref kind, ref places)
|
box(_, Rvalue::Aggregate(ref kind, ref places))
|
||||||
) = stmt.kind {
|
) = stmt.kind {
|
||||||
let (def_id, is_generator) = match kind {
|
let (def_id, is_generator) = match kind {
|
||||||
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
|
||||||
use rustc::middle::borrowck::SignalledError;
|
use rustc::middle::borrowck::SignalledError;
|
||||||
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef,
|
ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem,
|
||||||
Static, StaticKind
|
PlaceRef, Static, StaticKind
|
||||||
};
|
};
|
||||||
use rustc::mir::{Field, Projection, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
||||||
use rustc::mir::{Terminator, TerminatorKind};
|
use rustc::mir::{Terminator, TerminatorKind};
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
|
|
@ -546,7 +546,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
|
||||||
self.check_activations(location, span, flow_state);
|
self.check_activations(location, span, flow_state);
|
||||||
|
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::Assign(ref lhs, ref rhs) => {
|
StatementKind::Assign(box(ref lhs, ref rhs)) => {
|
||||||
self.consume_rvalue(
|
self.consume_rvalue(
|
||||||
location,
|
location,
|
||||||
(rhs, span),
|
(rhs, span),
|
||||||
|
|
@ -561,7 +561,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StatementKind::FakeRead(_, ref place) => {
|
StatementKind::FakeRead(_, box ref place) => {
|
||||||
// Read for match doesn't access any memory and is used to
|
// Read for match doesn't access any memory and is used to
|
||||||
// assert that a place is safe and live. So we don't have to
|
// assert that a place is safe and live. So we don't have to
|
||||||
// do any checks here.
|
// do any checks here.
|
||||||
|
|
@ -905,7 +905,7 @@ enum InitializationRequiringAction {
|
||||||
|
|
||||||
struct RootPlace<'d, 'tcx> {
|
struct RootPlace<'d, 'tcx> {
|
||||||
place_base: &'d PlaceBase<'tcx>,
|
place_base: &'d PlaceBase<'tcx>,
|
||||||
place_projection: &'d Option<Box<Projection<'tcx>>>,
|
place_projection: &'d [PlaceElem<'tcx>],
|
||||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1191,7 +1191,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
// before (at this point in the flow).
|
// before (at this point in the flow).
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = place_span.0 {
|
} = place_span.0 {
|
||||||
if let Mutability::Not = self.body.local_decls[*local].mutability {
|
if let Mutability::Not = self.body.local_decls[*local].mutability {
|
||||||
// check for reassignments to immutable local variables
|
// check for reassignments to immutable local variables
|
||||||
|
|
@ -1331,7 +1331,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
|
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
|
||||||
let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
|
let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
|
||||||
if place.projection.is_some() {
|
if !place.projection.is_empty() {
|
||||||
if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
|
if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
|
||||||
this.used_mut_upvars.push(field);
|
this.used_mut_upvars.push(field);
|
||||||
}
|
}
|
||||||
|
|
@ -1346,11 +1346,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
match *operand {
|
match *operand {
|
||||||
Operand::Move(Place {
|
Operand::Move(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) |
|
}) |
|
||||||
Operand::Copy(Place {
|
Operand::Copy(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) if self.body.local_decls[local].is_user_variable.is_none() => {
|
}) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||||
// The variable will be marked as mutable by the borrow.
|
// The variable will be marked as mutable by the borrow.
|
||||||
|
|
@ -1387,7 +1387,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let stmt = &bbd.statements[loc.statement_index];
|
let stmt = &bbd.statements[loc.statement_index];
|
||||||
debug!("temporary assigned in: stmt={:?}", stmt);
|
debug!("temporary assigned in: stmt={:?}", stmt);
|
||||||
|
|
||||||
if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind {
|
if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
|
||||||
propagate_closure_used_mut_place(self, source);
|
propagate_closure_used_mut_place(self, source);
|
||||||
} else {
|
} else {
|
||||||
bug!("closures should only capture user variables \
|
bug!("closures should only capture user variables \
|
||||||
|
|
@ -1468,7 +1468,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
//
|
//
|
||||||
// FIXME: allow thread-locals to borrow other thread locals?
|
// FIXME: allow thread-locals to borrow other thread locals?
|
||||||
|
|
||||||
assert!(root_place.projection.is_none());
|
assert!(root_place.projection.is_empty());
|
||||||
let (might_be_alive, will_be_dropped) = match root_place.base {
|
let (might_be_alive, will_be_dropped) = match root_place.base {
|
||||||
PlaceBase::Static(box Static {
|
PlaceBase::Static(box Static {
|
||||||
kind: StaticKind::Promoted(..),
|
kind: StaticKind::Promoted(..),
|
||||||
|
|
@ -1756,13 +1756,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
flow_state: &Flows<'cx, 'tcx>,
|
flow_state: &Flows<'cx, 'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||||
// recur down place; dispatch to external checks when necessary
|
|
||||||
let mut place_projection = &place.projection;
|
|
||||||
|
|
||||||
// None case => assigning to `x` does not require `x` be initialized.
|
// None case => assigning to `x` does not require `x` be initialized.
|
||||||
while let Some(proj) = place_projection {
|
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||||
let Projection { ref base, ref elem } = **proj;
|
match elem {
|
||||||
match *elem {
|
|
||||||
ProjectionElem::Index(_/*operand*/) |
|
ProjectionElem::Index(_/*operand*/) |
|
||||||
ProjectionElem::ConstantIndex { .. } |
|
ProjectionElem::ConstantIndex { .. } |
|
||||||
// assigning to P[i] requires P to be valid.
|
// assigning to P[i] requires P to be valid.
|
||||||
|
|
@ -1774,11 +1771,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
// assigning to (*P) requires P to be initialized
|
// assigning to (*P) requires P to be initialized
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Deref => {
|
||||||
|
let proj_base = &place.projection[..i];
|
||||||
|
|
||||||
self.check_if_full_path_is_moved(
|
self.check_if_full_path_is_moved(
|
||||||
location, InitializationRequiringAction::Use,
|
location, InitializationRequiringAction::Use,
|
||||||
(PlaceRef {
|
(PlaceRef {
|
||||||
base: &place.base,
|
base: &place.base,
|
||||||
projection: base,
|
projection: proj_base,
|
||||||
}, span), flow_state);
|
}, span), flow_state);
|
||||||
// (base initialized; no need to
|
// (base initialized; no need to
|
||||||
// recur further)
|
// recur further)
|
||||||
|
|
@ -1791,18 +1790,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionElem::Field(..) => {
|
ProjectionElem::Field(..) => {
|
||||||
|
let proj_base = &place.projection[..i];
|
||||||
// if type of `P` has a dtor, then
|
// if type of `P` has a dtor, then
|
||||||
// assigning to `P.f` requires `P` itself
|
// assigning to `P.f` requires `P` itself
|
||||||
// be already initialized
|
// be already initialized
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
|
let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
|
||||||
match base_ty.sty {
|
match base_ty.sty {
|
||||||
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
location, InitializationRequiringAction::Assignment,
|
location, InitializationRequiringAction::Assignment,
|
||||||
(PlaceRef {
|
(PlaceRef {
|
||||||
base: &place.base,
|
base: &place.base,
|
||||||
projection: base,
|
projection: proj_base,
|
||||||
}, span), flow_state);
|
}, span), flow_state);
|
||||||
|
|
||||||
// (base initialized; no need to
|
// (base initialized; no need to
|
||||||
|
|
@ -1815,7 +1815,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
ty::Adt(..) | ty::Tuple(..) => {
|
ty::Adt(..) | ty::Tuple(..) => {
|
||||||
check_parent_of_field(self, location, PlaceRef {
|
check_parent_of_field(self, location, PlaceRef {
|
||||||
base: &place.base,
|
base: &place.base,
|
||||||
projection: base,
|
projection: proj_base,
|
||||||
}, span, flow_state);
|
}, span, flow_state);
|
||||||
|
|
||||||
if let PlaceBase::Local(local) = place.base {
|
if let PlaceBase::Local(local) = place.base {
|
||||||
|
|
@ -1835,8 +1835,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
place_projection = base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_parent_of_field<'cx, 'tcx>(
|
fn check_parent_of_field<'cx, 'tcx>(
|
||||||
|
|
@ -2084,7 +2082,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
match root_place {
|
match root_place {
|
||||||
RootPlace {
|
RootPlace {
|
||||||
place_base: PlaceBase::Local(local),
|
place_base: PlaceBase::Local(local),
|
||||||
place_projection: None,
|
place_projection: [],
|
||||||
is_local_mutation_allowed,
|
is_local_mutation_allowed,
|
||||||
} => {
|
} => {
|
||||||
// If the local may have been initialized, and it is now currently being
|
// If the local may have been initialized, and it is now currently being
|
||||||
|
|
@ -2103,7 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
} => {}
|
} => {}
|
||||||
RootPlace {
|
RootPlace {
|
||||||
place_base,
|
place_base,
|
||||||
place_projection: place_projection @ Some(_),
|
place_projection: place_projection @ [.., _],
|
||||||
is_local_mutation_allowed: _,
|
is_local_mutation_allowed: _,
|
||||||
} => {
|
} => {
|
||||||
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
||||||
|
|
@ -2115,7 +2113,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
RootPlace {
|
RootPlace {
|
||||||
place_base: PlaceBase::Static(..),
|
place_base: PlaceBase::Static(..),
|
||||||
place_projection: None,
|
place_projection: [],
|
||||||
is_local_mutation_allowed: _,
|
is_local_mutation_allowed: _,
|
||||||
} => {}
|
} => {}
|
||||||
}
|
}
|
||||||
|
|
@ -2131,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
match place {
|
match place {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
let local = &self.body.local_decls[*local];
|
let local = &self.body.local_decls[*local];
|
||||||
match local.mutability {
|
match local.mutability {
|
||||||
|
|
@ -2162,7 +2160,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
kind: StaticKind::Promoted(..),
|
kind: StaticKind::Promoted(..),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} =>
|
} =>
|
||||||
Ok(RootPlace {
|
Ok(RootPlace {
|
||||||
place_base: place.base,
|
place_base: place.base,
|
||||||
|
|
@ -2175,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
def_id,
|
def_id,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
if !self.infcx.tcx.is_mutable_static(*def_id) {
|
if !self.infcx.tcx.is_mutable_static(*def_id) {
|
||||||
Err(place)
|
Err(place)
|
||||||
|
|
@ -2189,12 +2187,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection: Some(proj),
|
projection: [proj_base @ .., elem],
|
||||||
} => {
|
} => {
|
||||||
match proj.elem {
|
match elem {
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Deref => {
|
||||||
let base_ty =
|
let base_ty =
|
||||||
Place::ty_from(place.base, &proj.base, self.body, self.infcx.tcx).ty;
|
Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty;
|
||||||
|
|
||||||
// Check the kind of deref to decide
|
// Check the kind of deref to decide
|
||||||
match base_ty.sty {
|
match base_ty.sty {
|
||||||
|
|
@ -2216,7 +2214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
self.is_mutable(PlaceRef {
|
self.is_mutable(PlaceRef {
|
||||||
base: place.base,
|
base: place.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
}, mode)
|
}, mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2240,7 +2238,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
_ if base_ty.is_box() => {
|
_ if base_ty.is_box() => {
|
||||||
self.is_mutable(PlaceRef {
|
self.is_mutable(PlaceRef {
|
||||||
base: place.base,
|
base: place.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
}, is_local_mutation_allowed)
|
}, is_local_mutation_allowed)
|
||||||
}
|
}
|
||||||
// Deref should only be for reference, pointers or boxes
|
// Deref should only be for reference, pointers or boxes
|
||||||
|
|
@ -2297,7 +2295,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
// ```
|
// ```
|
||||||
let _ = self.is_mutable(PlaceRef {
|
let _ = self.is_mutable(PlaceRef {
|
||||||
base: place.base,
|
base: place.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
}, is_local_mutation_allowed)?;
|
}, is_local_mutation_allowed)?;
|
||||||
Ok(RootPlace {
|
Ok(RootPlace {
|
||||||
place_base: place.base,
|
place_base: place.base,
|
||||||
|
|
@ -2309,7 +2307,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
self.is_mutable(PlaceRef {
|
self.is_mutable(PlaceRef {
|
||||||
base: place.base,
|
base: place.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
}, is_local_mutation_allowed)
|
}, is_local_mutation_allowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2326,21 +2324,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let mut place_projection = place_ref.projection;
|
let mut place_projection = place_ref.projection;
|
||||||
let mut by_ref = false;
|
let mut by_ref = false;
|
||||||
|
|
||||||
if let Some(box Projection {
|
if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
|
||||||
base,
|
place_projection = proj_base;
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}) = place_projection {
|
|
||||||
place_projection = &base;
|
|
||||||
by_ref = true;
|
by_ref = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
match place_projection {
|
match place_projection {
|
||||||
Some(box Projection {
|
[base @ .., ProjectionElem::Field(field, _ty)] => {
|
||||||
base,
|
|
||||||
elem: ProjectionElem::Field(field, _ty),
|
|
||||||
}) => {
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let base_ty = Place::ty_from(place_ref.base, &base, self.body, tcx).ty;
|
let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty;
|
||||||
|
|
||||||
if (base_ty.is_closure() || base_ty.is_generator()) &&
|
if (base_ty.is_closure() || base_ty.is_generator()) &&
|
||||||
(!by_ref || self.upvars[field.index()].by_ref) {
|
(!by_ref || self.upvars[field.index()].by_ref) {
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// If that ever stops being the case, then the ever initialized
|
// If that ever stops being the case, then the ever initialized
|
||||||
// flow could be used.
|
// flow could be used.
|
||||||
if let Some(StatementKind::Assign(
|
if let Some(StatementKind::Assign(
|
||||||
Place {
|
box(
|
||||||
base: PlaceBase::Local(local),
|
Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(local),
|
||||||
},
|
projection: box [],
|
||||||
box Rvalue::Use(Operand::Move(move_from)),
|
},
|
||||||
|
Rvalue::Use(Operand::Move(move_from))
|
||||||
|
)
|
||||||
)) = self.body.basic_blocks()[location.block]
|
)) = self.body.basic_blocks()[location.block]
|
||||||
.statements
|
.statements
|
||||||
.get(location.statement_index)
|
.get(location.statement_index)
|
||||||
|
|
@ -274,16 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
span: Span
|
span: Span
|
||||||
) -> DiagnosticBuilder<'a> {
|
) -> DiagnosticBuilder<'a> {
|
||||||
let description = if place.projection.is_none() {
|
let description = if place.projection.is_empty() {
|
||||||
format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
|
format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
|
||||||
} else {
|
} else {
|
||||||
let mut base_static = &place.projection;
|
|
||||||
while let Some(box Projection { base: Some(ref proj), .. }) = base_static {
|
|
||||||
base_static = &proj.base;
|
|
||||||
}
|
|
||||||
let base_static = PlaceRef {
|
let base_static = PlaceRef {
|
||||||
base: &place.base,
|
base: &place.base,
|
||||||
projection: base_static,
|
projection: &place.projection[..1],
|
||||||
};
|
};
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -309,17 +307,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
|
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
|
||||||
.find_map(|p| self.is_upvar_field_projection(p));
|
.find_map(|p| self.is_upvar_field_projection(p));
|
||||||
|
|
||||||
let deref_base = match deref_target_place.projection {
|
let deref_base = match &deref_target_place.projection {
|
||||||
Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef {
|
box [proj_base @ .., ProjectionElem::Deref] => {
|
||||||
base: &deref_target_place.base,
|
PlaceRef {
|
||||||
projection: base,
|
base: &deref_target_place.base,
|
||||||
},
|
projection: proj_base,
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => bug!("deref_target_place is not a deref projection"),
|
_ => bug!("deref_target_place is not a deref projection"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let PlaceRef {
|
if let PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} = deref_base {
|
} = deref_base {
|
||||||
let decl = &self.body.local_decls[*local];
|
let decl = &self.body.local_decls[*local];
|
||||||
if decl.is_ref_for_guard() {
|
if decl.is_ref_for_guard() {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use rustc::hir;
|
||||||
use rustc::hir::Node;
|
use rustc::hir::Node;
|
||||||
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
|
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind
|
Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind
|
||||||
};
|
};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
@ -47,12 +47,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
match the_place_err {
|
match the_place_err {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(_),
|
base: PlaceBase::Local(_),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = access_place {
|
} = access_place {
|
||||||
reason = ", as it is not declared as mutable".to_string();
|
reason = ", as it is not declared as mutable".to_string();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -65,14 +65,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection:
|
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||||
Some(box Projection {
|
|
||||||
base,
|
|
||||||
elem: ProjectionElem::Field(upvar_index, _),
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
debug_assert!(is_closure_or_generator(
|
debug_assert!(is_closure_or_generator(
|
||||||
Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty
|
Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty
|
||||||
));
|
));
|
||||||
|
|
||||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||||
|
|
@ -86,14 +82,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection:
|
projection: [proj_base @ .., ProjectionElem::Deref],
|
||||||
Some(box Projection {
|
|
||||||
base,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
|
if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
|
||||||
base.is_none() &&
|
proj_base.is_empty() &&
|
||||||
!self.upvars.is_empty() {
|
!self.upvars.is_empty() {
|
||||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||||
debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
|
debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
|
||||||
|
|
@ -114,7 +106,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
", as `Fn` closures cannot mutate their captured variables".to_string()
|
", as `Fn` closures cannot mutate their captured variables".to_string()
|
||||||
}
|
}
|
||||||
} else if {
|
} else if {
|
||||||
if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) {
|
if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) {
|
||||||
self.body.local_decls[*local].is_ref_for_guard()
|
self.body.local_decls[*local].is_ref_for_guard()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
@ -125,7 +117,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
let source = self.borrowed_content_source(PlaceRef {
|
let source = self.borrowed_content_source(PlaceRef {
|
||||||
base: the_place_err.base,
|
base: the_place_err.base,
|
||||||
projection: base,
|
projection: proj_base,
|
||||||
});
|
});
|
||||||
let pointer_type = source.describe_for_immutable_place();
|
let pointer_type = source.describe_for_immutable_place();
|
||||||
opt_source = Some(source);
|
opt_source = Some(source);
|
||||||
|
|
@ -151,7 +143,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
kind: StaticKind::Promoted(..),
|
kind: StaticKind::Promoted(..),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => unreachable!(),
|
} => unreachable!(),
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
|
|
@ -161,11 +153,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
def_id,
|
def_id,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Static(_),
|
base: PlaceBase::Static(_),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = access_place {
|
} = access_place {
|
||||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||||
reason = String::new();
|
reason = String::new();
|
||||||
|
|
@ -178,33 +170,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection:
|
projection: [.., ProjectionElem::Index(_)],
|
||||||
Some(box Projection {
|
|
||||||
base: _,
|
|
||||||
elem: ProjectionElem::Index(_),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
| PlaceRef {
|
| PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection:
|
projection: [.., ProjectionElem::ConstantIndex { .. }],
|
||||||
Some(box Projection {
|
|
||||||
base: _,
|
|
||||||
elem: ProjectionElem::ConstantIndex { .. },
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
| PlaceRef {
|
| PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection: Some(box Projection {
|
projection: [.., ProjectionElem::Subslice { .. }],
|
||||||
base: _,
|
|
||||||
elem: ProjectionElem::Subslice { .. },
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
| PlaceRef {
|
| PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection: Some(box Projection {
|
projection: [.., ProjectionElem::Downcast(..)],
|
||||||
base: _,
|
|
||||||
elem: ProjectionElem::Downcast(..),
|
|
||||||
}),
|
|
||||||
} => bug!("Unexpected immutable place."),
|
} => bug!("Unexpected immutable place."),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,22 +240,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// after the field access).
|
// after the field access).
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(box Projection {
|
projection: [proj_base @ ..,
|
||||||
base: Some(box Projection {
|
ProjectionElem::Deref,
|
||||||
base: Some(box Projection {
|
ProjectionElem::Field(field, _),
|
||||||
base: base_proj,
|
ProjectionElem::Deref,
|
||||||
elem: ProjectionElem::Deref,
|
],
|
||||||
}),
|
|
||||||
elem: ProjectionElem::Field(field, _),
|
|
||||||
}),
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||||
|
|
||||||
if let Some((span, message)) = annotate_struct_field(
|
if let Some((span, message)) = annotate_struct_field(
|
||||||
self.infcx.tcx,
|
self.infcx.tcx,
|
||||||
Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty,
|
Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty,
|
||||||
field,
|
field,
|
||||||
) {
|
) {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
|
|
@ -292,7 +265,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// Suggest removing a `&mut` from the use of a mutable reference.
|
// Suggest removing a `&mut` from the use of a mutable reference.
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} if {
|
} if {
|
||||||
self.body.local_decls.get(*local).map(|local_decl| {
|
self.body.local_decls.get(*local).map(|local_decl| {
|
||||||
if let ClearCrossCrate::Set(
|
if let ClearCrossCrate::Set(
|
||||||
|
|
@ -328,7 +301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// variable) mutations...
|
// variable) mutations...
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} if self.body.local_decls[*local].can_be_made_mutable() => {
|
} if self.body.local_decls[*local].can_be_made_mutable() => {
|
||||||
// ... but it doesn't make sense to suggest it on
|
// ... but it doesn't make sense to suggest it on
|
||||||
// variables that are `ref x`, `ref mut x`, `&self`,
|
// variables that are `ref x`, `ref mut x`, `&self`,
|
||||||
|
|
@ -349,13 +322,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// Also suggest adding mut for upvars
|
// Also suggest adding mut for upvars
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(box Projection {
|
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||||
base: proj_base,
|
|
||||||
elem: ProjectionElem::Field(upvar_index, _),
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
debug_assert!(is_closure_or_generator(
|
debug_assert!(is_closure_or_generator(
|
||||||
Place::ty_from(&base, &proj_base, self.body, self.infcx.tcx).ty
|
Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty
|
||||||
));
|
));
|
||||||
|
|
||||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||||
|
|
@ -385,7 +355,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// a local variable, then just suggest the user remove it.
|
// a local variable, then just suggest the user remove it.
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(_),
|
base: PlaceBase::Local(_),
|
||||||
projection: None,
|
projection: [],
|
||||||
} if {
|
} if {
|
||||||
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||||
snippet.starts_with("&mut ")
|
snippet.starts_with("&mut ")
|
||||||
|
|
@ -400,10 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(box Projection {
|
projection: [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} if {
|
} if {
|
||||||
if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
|
if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
|
||||||
self.body.local_decls[*local].is_user_variable
|
self.body.local_decls[*local].is_user_variable
|
||||||
|
|
@ -427,10 +394,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
// arbitrary base for the projection?
|
// arbitrary base for the projection?
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(box Projection {
|
projection: [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} if self.body.local_decls[*local].is_user_variable.is_some() =>
|
} if self.body.local_decls[*local].is_user_variable.is_some() =>
|
||||||
{
|
{
|
||||||
let local_decl = &self.body.local_decls[*local];
|
let local_decl = &self.body.local_decls[*local];
|
||||||
|
|
@ -510,10 +474,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: Some(box Projection {
|
projection: [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
// FIXME document what is this 1 magic number about
|
// FIXME document what is this 1 magic number about
|
||||||
} if *base == PlaceBase::Local(Local::new(1)) &&
|
} if *base == PlaceBase::Local(Local::new(1)) &&
|
||||||
!self.upvars.is_empty() =>
|
!self.upvars.is_empty() =>
|
||||||
|
|
@ -527,10 +488,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection: Some(box Projection {
|
projection: [.., ProjectionElem::Deref],
|
||||||
base: _,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,8 @@ use rustc::infer::InferCtxt;
|
||||||
use rustc::mir::visit::TyContext;
|
use rustc::mir::visit::TyContext;
|
||||||
use rustc::mir::visit::Visitor;
|
use rustc::mir::visit::Visitor;
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
|
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
|
||||||
ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
|
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||||
UserTypeProjection,
|
|
||||||
};
|
};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
|
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
|
||||||
|
|
@ -229,14 +228,11 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
||||||
match place {
|
match place {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} |
|
} |
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(box Projection {
|
projection: box [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
debug!(
|
debug!(
|
||||||
"Recording `killed` facts for borrows of local={:?} at location={:?}",
|
"Recording `killed` facts for borrows of local={:?} at location={:?}",
|
||||||
|
|
@ -261,7 +257,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
||||||
|
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(_),
|
projection: box [.., _],
|
||||||
} => {
|
} => {
|
||||||
// Kill conflicting borrows of the innermost local.
|
// Kill conflicting borrows of the innermost local.
|
||||||
debug!(
|
debug!(
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(borrowed_local),
|
base: PlaceBase::Local(borrowed_local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = place {
|
} = place {
|
||||||
if body.local_decls[*borrowed_local].name.is_some()
|
if body.local_decls[*borrowed_local].name.is_some()
|
||||||
&& local != *borrowed_local
|
&& local != *borrowed_local
|
||||||
|
|
@ -495,11 +495,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
Operand::Constant(c) => c.span,
|
Operand::Constant(c) => c.span,
|
||||||
Operand::Copy(Place {
|
Operand::Copy(Place {
|
||||||
base: PlaceBase::Local(l),
|
base: PlaceBase::Local(l),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) |
|
}) |
|
||||||
Operand::Move(Place {
|
Operand::Move(Place {
|
||||||
base: PlaceBase::Local(l),
|
base: PlaceBase::Local(l),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) => {
|
}) => {
|
||||||
let local_decl = &self.body.local_decls[*l];
|
let local_decl = &self.body.local_decls[*l];
|
||||||
if local_decl.name.is_none() {
|
if local_decl.name.is_none() {
|
||||||
|
|
@ -541,10 +541,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
// it which simplifies the termination logic.
|
// it which simplifies the termination logic.
|
||||||
let mut queue = vec![location];
|
let mut queue = vec![location];
|
||||||
let mut target = if let Some(&Statement {
|
let mut target = if let Some(&Statement {
|
||||||
kind: StatementKind::Assign(Place {
|
kind: StatementKind::Assign(box(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, _),
|
}, _)),
|
||||||
..
|
..
|
||||||
}) = stmt
|
}) = stmt
|
||||||
{
|
{
|
||||||
|
|
@ -567,7 +567,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
debug!("was_captured_by_trait_object: stmt={:?}", stmt);
|
debug!("was_captured_by_trait_object: stmt={:?}", stmt);
|
||||||
|
|
||||||
// The only kind of statement that we care about is assignments...
|
// The only kind of statement that we care about is assignments...
|
||||||
if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
|
if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
|
||||||
let into = match place.local_or_deref_local() {
|
let into = match place.local_or_deref_local() {
|
||||||
Some(into) => into,
|
Some(into) => into,
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -583,11 +583,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
Rvalue::Use(operand) => match operand {
|
Rvalue::Use(operand) => match operand {
|
||||||
Operand::Copy(Place {
|
Operand::Copy(Place {
|
||||||
base: PlaceBase::Local(from),
|
base: PlaceBase::Local(from),
|
||||||
projection: None,
|
projection: box [],
|
||||||
})
|
})
|
||||||
| Operand::Move(Place {
|
| Operand::Move(Place {
|
||||||
base: PlaceBase::Local(from),
|
base: PlaceBase::Local(from),
|
||||||
projection: None,
|
projection: box [],
|
||||||
})
|
})
|
||||||
if *from == target =>
|
if *from == target =>
|
||||||
{
|
{
|
||||||
|
|
@ -602,11 +602,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
) => match operand {
|
) => match operand {
|
||||||
Operand::Copy(Place {
|
Operand::Copy(Place {
|
||||||
base: PlaceBase::Local(from),
|
base: PlaceBase::Local(from),
|
||||||
projection: None,
|
projection: box [],
|
||||||
})
|
})
|
||||||
| Operand::Move(Place {
|
| Operand::Move(Place {
|
||||||
base: PlaceBase::Local(from),
|
base: PlaceBase::Local(from),
|
||||||
projection: None,
|
projection: box [],
|
||||||
})
|
})
|
||||||
if *from == target =>
|
if *from == target =>
|
||||||
{
|
{
|
||||||
|
|
@ -639,7 +639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if let TerminatorKind::Call {
|
if let TerminatorKind::Call {
|
||||||
destination: Some((Place {
|
destination: Some((Place {
|
||||||
base: PlaceBase::Local(dest),
|
base: PlaceBase::Local(dest),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, block)),
|
}, block)),
|
||||||
args,
|
args,
|
||||||
..
|
..
|
||||||
|
|
@ -653,7 +653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let found_target = args.iter().any(|arg| {
|
let found_target = args.iter().any(|arg| {
|
||||||
if let Operand::Move(Place {
|
if let Operand::Move(Place {
|
||||||
base: PlaceBase::Local(potential),
|
base: PlaceBase::Local(potential),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) = arg {
|
}) = arg {
|
||||||
*potential == target
|
*potential == target
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
self.check_activations(location);
|
self.check_activations(location);
|
||||||
|
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(ref lhs, ref rhs) => {
|
StatementKind::Assign(box(ref lhs, ref rhs)) => {
|
||||||
self.consume_rvalue(
|
self.consume_rvalue(
|
||||||
location,
|
location,
|
||||||
rhs,
|
rhs,
|
||||||
|
|
|
||||||
|
|
@ -421,107 +421,104 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
) -> PlaceTy<'tcx> {
|
) -> PlaceTy<'tcx> {
|
||||||
debug!("sanitize_place: {:?}", place);
|
debug!("sanitize_place: {:?}", place);
|
||||||
|
|
||||||
place.iterate(|place_base, place_projection| {
|
let mut place_ty = match &place.base {
|
||||||
let mut place_ty = match place_base {
|
PlaceBase::Local(index) =>
|
||||||
PlaceBase::Local(index) =>
|
PlaceTy::from_ty(self.body.local_decls[*index].ty),
|
||||||
PlaceTy::from_ty(self.body.local_decls[*index].ty),
|
PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
|
||||||
PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
|
let sty = self.sanitize_type(place, sty);
|
||||||
let sty = self.sanitize_type(place, sty);
|
let check_err =
|
||||||
let check_err =
|
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|
||||||
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|
place: &Place<'tcx>,
|
||||||
place: &Place<'tcx>,
|
ty,
|
||||||
ty,
|
sty| {
|
||||||
sty| {
|
if let Err(terr) = verifier.cx.eq_types(
|
||||||
if let Err(terr) = verifier.cx.eq_types(
|
sty,
|
||||||
sty,
|
ty,
|
||||||
ty,
|
location.to_locations(),
|
||||||
location.to_locations(),
|
ConstraintCategory::Boring,
|
||||||
ConstraintCategory::Boring,
|
) {
|
||||||
) {
|
span_mirbug!(
|
||||||
span_mirbug!(
|
verifier,
|
||||||
verifier,
|
place,
|
||||||
place,
|
"bad promoted type ({:?}: {:?}): {:?}",
|
||||||
"bad promoted type ({:?}: {:?}): {:?}",
|
ty,
|
||||||
ty,
|
sty,
|
||||||
sty,
|
terr
|
||||||
terr
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
match kind {
|
};
|
||||||
StaticKind::Promoted(promoted, _) => {
|
match kind {
|
||||||
if !self.errors_reported {
|
StaticKind::Promoted(promoted, _) => {
|
||||||
let promoted_body = &self.promoted[*promoted];
|
if !self.errors_reported {
|
||||||
self.sanitize_promoted(promoted_body, location);
|
let promoted_body = &self.promoted[*promoted];
|
||||||
|
self.sanitize_promoted(promoted_body, location);
|
||||||
|
|
||||||
let promoted_ty = promoted_body.return_ty();
|
let promoted_ty = promoted_body.return_ty();
|
||||||
check_err(self, place, promoted_ty, sty);
|
check_err(self, place, promoted_ty, sty);
|
||||||
}
|
|
||||||
}
|
|
||||||
StaticKind::Static => {
|
|
||||||
let ty = self.tcx().type_of(*def_id);
|
|
||||||
let ty = self.cx.normalize(ty, location);
|
|
||||||
|
|
||||||
check_err(self, place, ty, sty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlaceTy::from_ty(sty)
|
StaticKind::Static => {
|
||||||
}
|
let ty = self.tcx().type_of(*def_id);
|
||||||
};
|
let ty = self.cx.normalize(ty, location);
|
||||||
|
|
||||||
// FIXME use place_projection.is_empty() when is available
|
check_err(self, place, ty, sty);
|
||||||
if place.projection.is_none() {
|
}
|
||||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
}
|
||||||
let is_promoted = match place {
|
PlaceTy::from_ty(sty)
|
||||||
Place {
|
}
|
||||||
base: PlaceBase::Static(box Static {
|
};
|
||||||
kind: StaticKind::Promoted(..),
|
|
||||||
..
|
if place.projection.is_empty() {
|
||||||
}),
|
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||||
projection: None,
|
let is_promoted = match place {
|
||||||
} => true,
|
Place {
|
||||||
_ => false,
|
base: PlaceBase::Static(box Static {
|
||||||
|
kind: StaticKind::Promoted(..),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
projection: box [],
|
||||||
|
} => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_promoted {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let trait_ref = ty::TraitRef {
|
||||||
|
def_id: tcx.lang_items().copy_trait().unwrap(),
|
||||||
|
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_promoted {
|
// To have a `Copy` operand, the type `T` of the
|
||||||
let tcx = self.tcx();
|
// value must be `Copy`. Note that we prove that `T: Copy`,
|
||||||
let trait_ref = ty::TraitRef {
|
// rather than using the `is_copy_modulo_regions`
|
||||||
def_id: tcx.lang_items().copy_trait().unwrap(),
|
// test. This is important because
|
||||||
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
|
// `is_copy_modulo_regions` ignores the resulting region
|
||||||
};
|
// obligations and assumes they pass. This can result in
|
||||||
|
// bounds from `Copy` impls being unsoundly ignored (e.g.,
|
||||||
// In order to have a Copy operand, the type T of the
|
// #29149). Note that we decide to use `Copy` before knowing
|
||||||
// value must be Copy. Note that we prove that T: Copy,
|
// whether the bounds fully apply: in effect, the rule is
|
||||||
// rather than using the `is_copy_modulo_regions`
|
// that if a value of some type could implement `Copy`, then
|
||||||
// test. This is important because
|
// it must.
|
||||||
// `is_copy_modulo_regions` ignores the resulting region
|
self.cx.prove_trait_ref(
|
||||||
// obligations and assumes they pass. This can result in
|
trait_ref,
|
||||||
// bounds from Copy impls being unsoundly ignored (e.g.,
|
location.to_locations(),
|
||||||
// #29149). Note that we decide to use Copy before knowing
|
ConstraintCategory::CopyBound,
|
||||||
// whether the bounds fully apply: in effect, the rule is
|
);
|
||||||
// that if a value of some type could implement Copy, then
|
|
||||||
// it must.
|
|
||||||
self.cx.prove_trait_ref(
|
|
||||||
trait_ref,
|
|
||||||
location.to_locations(),
|
|
||||||
ConstraintCategory::CopyBound,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for proj in place_projection {
|
for elem in place.projection.iter() {
|
||||||
if place_ty.variant_index.is_none() {
|
if place_ty.variant_index.is_none() {
|
||||||
if place_ty.ty.references_error() {
|
if place_ty.ty.references_error() {
|
||||||
assert!(self.errors_reported);
|
assert!(self.errors_reported);
|
||||||
return PlaceTy::from_ty(self.tcx().types.err);
|
return PlaceTy::from_ty(self.tcx().types.err);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
|
|
||||||
}
|
}
|
||||||
|
place_ty = self.sanitize_projection(place_ty, elem, place, location)
|
||||||
|
}
|
||||||
|
|
||||||
place_ty
|
place_ty
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
|
fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
|
||||||
|
|
@ -1346,7 +1343,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
debug!("check_stmt: {:?}", stmt);
|
debug!("check_stmt: {:?}", stmt);
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::Assign(ref place, ref rv) => {
|
StatementKind::Assign(box(ref place, ref rv)) => {
|
||||||
// Assignments to temporaries are not "interesting";
|
// Assignments to temporaries are not "interesting";
|
||||||
// they are not caused by the user, but rather artifacts
|
// they are not caused by the user, but rather artifacts
|
||||||
// of lowering. Assignments to other sorts of places *are* interesting
|
// of lowering. Assignments to other sorts of places *are* interesting
|
||||||
|
|
@ -1354,7 +1351,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let category = match *place {
|
let category = match *place {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(RETURN_PLACE),
|
base: PlaceBase::Local(RETURN_PLACE),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} => if let BorrowCheckContext {
|
} => if let BorrowCheckContext {
|
||||||
universal_regions:
|
universal_regions:
|
||||||
UniversalRegions {
|
UniversalRegions {
|
||||||
|
|
@ -1373,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(l),
|
base: PlaceBase::Local(l),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||||
ConstraintCategory::Boring
|
ConstraintCategory::Boring
|
||||||
}
|
}
|
||||||
|
|
@ -1453,7 +1450,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
StatementKind::AscribeUserType(ref place, variance, box ref projection) => {
|
StatementKind::AscribeUserType(box(ref place, ref projection), variance) => {
|
||||||
let place_ty = place.ty(body, tcx).ty;
|
let place_ty = place.ty(body, tcx).ty;
|
||||||
if let Err(terr) = self.relate_type_and_user_type(
|
if let Err(terr) = self.relate_type_and_user_type(
|
||||||
place_ty,
|
place_ty,
|
||||||
|
|
@ -1660,7 +1657,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let category = match *dest {
|
let category = match *dest {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(RETURN_PLACE),
|
base: PlaceBase::Local(RETURN_PLACE),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} => {
|
} => {
|
||||||
if let BorrowCheckContext {
|
if let BorrowCheckContext {
|
||||||
universal_regions:
|
universal_regions:
|
||||||
|
|
@ -1682,7 +1679,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(l),
|
base: PlaceBase::Local(l),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||||
ConstraintCategory::Boring
|
ConstraintCategory::Boring
|
||||||
}
|
}
|
||||||
|
|
@ -2416,19 +2413,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// *p`, where the `p` has type `&'b mut Foo`, for example, we
|
// *p`, where the `p` has type `&'b mut Foo`, for example, we
|
||||||
// need to ensure that `'b: 'a`.
|
// need to ensure that `'b: 'a`.
|
||||||
|
|
||||||
let mut borrowed_projection = &borrowed_place.projection;
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"add_reborrow_constraint({:?}, {:?}, {:?})",
|
"add_reborrow_constraint({:?}, {:?}, {:?})",
|
||||||
location, borrow_region, borrowed_place
|
location, borrow_region, borrowed_place
|
||||||
);
|
);
|
||||||
while let Some(box proj) = borrowed_projection {
|
for (i, elem) in borrowed_place.projection.iter().enumerate().rev() {
|
||||||
debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection);
|
debug!("add_reborrow_constraint - iteration {:?}", elem);
|
||||||
|
let proj_base = &borrowed_place.projection[..i];
|
||||||
|
|
||||||
match proj.elem {
|
match elem {
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Deref => {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty;
|
let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
|
||||||
|
|
||||||
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
|
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
|
||||||
match base_ty.sty {
|
match base_ty.sty {
|
||||||
|
|
@ -2490,10 +2486,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// other field access
|
// other field access
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "propagate" case. We need to check that our base is valid
|
|
||||||
// for the borrow's lifetime.
|
|
||||||
borrowed_projection = &proj.base;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,55 +25,54 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
locals_state_at_exit: &LocalsStateAtExit,
|
locals_state_at_exit: &LocalsStateAtExit,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.iterate(|place_base, place_projection| {
|
let ignore = match self.base {
|
||||||
let ignore = match place_base {
|
// If a local variable is immutable, then we only need to track borrows to guard
|
||||||
// If a local variable is immutable, then we only need to track borrows to guard
|
// against two kinds of errors:
|
||||||
// against two kinds of errors:
|
// * The variable being dropped while still borrowed (e.g., because the fn returns
|
||||||
// * The variable being dropped while still borrowed (e.g., because the fn returns
|
// a reference to a local variable)
|
||||||
// a reference to a local variable)
|
// * The variable being moved while still borrowed
|
||||||
// * The variable being moved while still borrowed
|
//
|
||||||
//
|
// In particular, the variable cannot be mutated -- the "access checks" will fail --
|
||||||
// In particular, the variable cannot be mutated -- the "access checks" will fail --
|
// so we don't have to worry about mutation while borrowed.
|
||||||
// so we don't have to worry about mutation while borrowed.
|
PlaceBase::Local(index) => {
|
||||||
PlaceBase::Local(index) => {
|
match locals_state_at_exit {
|
||||||
match locals_state_at_exit {
|
LocalsStateAtExit::AllAreInvalidated => false,
|
||||||
LocalsStateAtExit::AllAreInvalidated => false,
|
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
|
||||||
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
|
let ignore = !has_storage_dead_or_moved.contains(index) &&
|
||||||
let ignore = !has_storage_dead_or_moved.contains(*index) &&
|
body.local_decls[index].mutability == Mutability::Not;
|
||||||
body.local_decls[*index].mutability == Mutability::Not;
|
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
|
||||||
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
|
ignore
|
||||||
ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
|
|
||||||
false,
|
|
||||||
PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
|
|
||||||
tcx.is_mutable_static(*def_id)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for proj in place_projection {
|
|
||||||
if proj.elem == ProjectionElem::Deref {
|
|
||||||
let ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
|
|
||||||
match ty.sty {
|
|
||||||
// For both derefs of raw pointers and `&T`
|
|
||||||
// references, the original path is `Copy` and
|
|
||||||
// therefore not significant. In particular,
|
|
||||||
// there is nothing the user can do to the
|
|
||||||
// original path that would invalidate the
|
|
||||||
// newly created reference -- and if there
|
|
||||||
// were, then the user could have copied the
|
|
||||||
// original path into a new variable and
|
|
||||||
// borrowed *that* one, leaving the original
|
|
||||||
// path unborrowed.
|
|
||||||
ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
|
||||||
|
false,
|
||||||
|
PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
|
||||||
|
tcx.is_mutable_static(def_id)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ignore
|
for (i, elem) in self.projection.iter().enumerate() {
|
||||||
})
|
let proj_base = &self.projection[..i];
|
||||||
|
|
||||||
|
if *elem == ProjectionElem::Deref {
|
||||||
|
let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
|
||||||
|
if let ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) = ty.sty {
|
||||||
|
// For both derefs of raw pointers and `&T`
|
||||||
|
// references, the original path is `Copy` and
|
||||||
|
// therefore not significant. In particular,
|
||||||
|
// there is nothing the user can do to the
|
||||||
|
// original path that would invalidate the
|
||||||
|
// newly created reference -- and if there
|
||||||
|
// were, then the user could have copied the
|
||||||
|
// original path into a new variable and
|
||||||
|
// borrowed *that* one, leaving the original
|
||||||
|
// path unborrowed.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ use crate::borrow_check::Overlap;
|
||||||
use crate::borrow_check::{Deep, Shallow, AccessDepth};
|
use crate::borrow_check::{Deep, Shallow, AccessDepth};
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
|
Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
|
||||||
StaticKind,
|
|
||||||
};
|
};
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
|
@ -67,39 +66,35 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
|
||||||
// it's so common that it's a speed win to check for it first.
|
// it's so common that it's a speed win to check for it first.
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(l1),
|
base: PlaceBase::Local(l1),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = borrow_place {
|
} = borrow_place {
|
||||||
if let PlaceRef {
|
if let PlaceRef {
|
||||||
base: PlaceBase::Local(l2),
|
base: PlaceBase::Local(l2),
|
||||||
projection: None,
|
projection: [],
|
||||||
} = access_place {
|
} = access_place {
|
||||||
return l1 == l2;
|
return l1 == l2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
borrow_place.iterate(|borrow_base, borrow_projections| {
|
place_components_conflict(
|
||||||
access_place.iterate(|access_base, access_projections| {
|
tcx,
|
||||||
place_components_conflict(
|
param_env,
|
||||||
tcx,
|
body,
|
||||||
param_env,
|
borrow_place,
|
||||||
body,
|
borrow_kind,
|
||||||
(borrow_base, borrow_projections),
|
access_place,
|
||||||
borrow_kind,
|
access,
|
||||||
(access_base, access_projections),
|
bias,
|
||||||
access,
|
)
|
||||||
bias,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place_components_conflict<'tcx>(
|
fn place_components_conflict<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
|
borrow_place: &Place<'tcx>,
|
||||||
borrow_kind: BorrowKind,
|
borrow_kind: BorrowKind,
|
||||||
access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
|
access_place: PlaceRef<'_, 'tcx>,
|
||||||
access: AccessDepth,
|
access: AccessDepth,
|
||||||
bias: PlaceConflictBias,
|
bias: PlaceConflictBias,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
@ -145,8 +140,8 @@ fn place_components_conflict<'tcx>(
|
||||||
// and either equal or disjoint.
|
// and either equal or disjoint.
|
||||||
// - If we did run out of access, the borrow can access a part of it.
|
// - If we did run out of access, the borrow can access a part of it.
|
||||||
|
|
||||||
let borrow_base = borrow_projections.0;
|
let borrow_base = &borrow_place.base;
|
||||||
let access_base = access_projections.0;
|
let access_base = access_place.base;
|
||||||
|
|
||||||
match place_base_conflict(tcx, param_env, borrow_base, access_base) {
|
match place_base_conflict(tcx, param_env, borrow_base, access_base) {
|
||||||
Overlap::Arbitrary => {
|
Overlap::Arbitrary => {
|
||||||
|
|
@ -163,147 +158,157 @@ fn place_components_conflict<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut borrow_projections = borrow_projections.1;
|
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
|
||||||
let mut access_projections = access_projections.1;
|
for (i, (borrow_c, access_c)) in
|
||||||
|
borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
|
||||||
|
{
|
||||||
|
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
||||||
|
let borrow_proj_base = &borrow_place.projection[..i];
|
||||||
|
|
||||||
loop {
|
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
||||||
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
|
|
||||||
if let Some(borrow_c) = borrow_projections.next() {
|
|
||||||
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
|
||||||
|
|
||||||
if let Some(access_c) = access_projections.next() {
|
// Borrow and access path both have more components.
|
||||||
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
//
|
||||||
|
// Examples:
|
||||||
// Borrow and access path both have more components.
|
//
|
||||||
|
// - borrow of `a.(...)`, access to `a.(...)`
|
||||||
|
// - borrow of `a.(...)`, access to `b.(...)`
|
||||||
|
//
|
||||||
|
// Here we only see the components we have checked so
|
||||||
|
// far (in our examples, just the first component). We
|
||||||
|
// check whether the components being borrowed vs
|
||||||
|
// accessed are disjoint (as in the second example,
|
||||||
|
// but not the first).
|
||||||
|
match place_projection_conflict(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
borrow_base,
|
||||||
|
borrow_proj_base,
|
||||||
|
borrow_c,
|
||||||
|
access_c,
|
||||||
|
bias,
|
||||||
|
) {
|
||||||
|
Overlap::Arbitrary => {
|
||||||
|
// We have encountered different fields of potentially
|
||||||
|
// the same union - the borrow now partially overlaps.
|
||||||
//
|
//
|
||||||
// Examples:
|
// There is no *easy* way of comparing the fields
|
||||||
|
// further on, because they might have different types
|
||||||
|
// (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
|
||||||
|
// `.y` come from different structs).
|
||||||
//
|
//
|
||||||
// - borrow of `a.(...)`, access to `a.(...)`
|
// We could try to do some things here - e.g., count
|
||||||
// - borrow of `a.(...)`, access to `b.(...)`
|
// dereferences - but that's probably not a good
|
||||||
//
|
// idea, at least for now, so just give up and
|
||||||
// Here we only see the components we have checked so
|
// report a conflict. This is unsafe code anyway so
|
||||||
// far (in our examples, just the first component). We
|
// the user could always use raw pointers.
|
||||||
// check whether the components being borrowed vs
|
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
||||||
// accessed are disjoint (as in the second example,
|
|
||||||
// but not the first).
|
|
||||||
match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) {
|
|
||||||
Overlap::Arbitrary => {
|
|
||||||
// We have encountered different fields of potentially
|
|
||||||
// the same union - the borrow now partially overlaps.
|
|
||||||
//
|
|
||||||
// There is no *easy* way of comparing the fields
|
|
||||||
// further on, because they might have different types
|
|
||||||
// (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
|
|
||||||
// `.y` come from different structs).
|
|
||||||
//
|
|
||||||
// We could try to do some things here - e.g., count
|
|
||||||
// dereferences - but that's probably not a good
|
|
||||||
// idea, at least for now, so just give up and
|
|
||||||
// report a conflict. This is unsafe code anyway so
|
|
||||||
// the user could always use raw pointers.
|
|
||||||
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Overlap::EqualOrDisjoint => {
|
|
||||||
// This is the recursive case - proceed to the next element.
|
|
||||||
}
|
|
||||||
Overlap::Disjoint => {
|
|
||||||
// We have proven the borrow disjoint - further
|
|
||||||
// projections will remain disjoint.
|
|
||||||
debug!("borrow_conflicts_with_place: disjoint");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Borrow path is longer than the access path. Examples:
|
|
||||||
//
|
|
||||||
// - borrow of `a.b.c`, access to `a.b`
|
|
||||||
//
|
|
||||||
// Here, we know that the borrow can access a part of
|
|
||||||
// our place. This is a conflict if that is a part our
|
|
||||||
// access cares about.
|
|
||||||
|
|
||||||
let base = &borrow_c.base;
|
|
||||||
let elem = &borrow_c.elem;
|
|
||||||
let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty;
|
|
||||||
|
|
||||||
match (elem, &base_ty.sty, access) {
|
|
||||||
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
|
||||||
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
|
||||||
// The array length is like additional fields on the
|
|
||||||
// type; it does not overlap any existing data there.
|
|
||||||
// Furthermore, if cannot actually be a prefix of any
|
|
||||||
// borrowed place (at least in MIR as it is currently.)
|
|
||||||
//
|
|
||||||
// e.g., a (mutable) borrow of `a[5]` while we read the
|
|
||||||
// array length of `a`.
|
|
||||||
debug!("borrow_conflicts_with_place: implicit field");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
(ProjectionElem::Deref, _, Shallow(None)) => {
|
|
||||||
// e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
|
|
||||||
// prefix thereof - the shallow access can't touch anything behind
|
|
||||||
// the pointer.
|
|
||||||
debug!("borrow_conflicts_with_place: shallow access behind ptr");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
|
|
||||||
// Shouldn't be tracked
|
|
||||||
bug!("Tracking borrow behind shared reference.");
|
|
||||||
}
|
|
||||||
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
|
|
||||||
// Values behind a mutable reference are not access either by dropping a
|
|
||||||
// value, or by StorageDead
|
|
||||||
debug!("borrow_conflicts_with_place: drop access behind ptr");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
(ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
|
|
||||||
// Drop can read/write arbitrary projections, so places
|
|
||||||
// conflict regardless of further projections.
|
|
||||||
if def.has_dtor(tcx) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(ProjectionElem::Deref, _, Deep)
|
|
||||||
| (ProjectionElem::Deref, _, AccessDepth::Drop)
|
|
||||||
| (ProjectionElem::Field { .. }, _, _)
|
|
||||||
| (ProjectionElem::Index { .. }, _, _)
|
|
||||||
| (ProjectionElem::ConstantIndex { .. }, _, _)
|
|
||||||
| (ProjectionElem::Subslice { .. }, _, _)
|
|
||||||
| (ProjectionElem::Downcast { .. }, _, _) => {
|
|
||||||
// Recursive case. This can still be disjoint on a
|
|
||||||
// further iteration if this a shallow access and
|
|
||||||
// there's a deref later on, e.g., a borrow
|
|
||||||
// of `*x.y` while accessing `x`.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Borrow path ran out but access path may not
|
|
||||||
// have. Examples:
|
|
||||||
//
|
|
||||||
// - borrow of `a.b`, access to `a.b.c`
|
|
||||||
// - borrow of `a.b`, access to `a.b`
|
|
||||||
//
|
|
||||||
// In the first example, where we didn't run out of
|
|
||||||
// access, the borrow can access all of our place, so we
|
|
||||||
// have a conflict.
|
|
||||||
//
|
|
||||||
// If the second example, where we did, then we still know
|
|
||||||
// that the borrow can access a *part* of our place that
|
|
||||||
// our access cares about, so we still have a conflict.
|
|
||||||
if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() {
|
|
||||||
debug!("borrow_conflicts_with_place: shallow borrow");
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Overlap::EqualOrDisjoint => {
|
||||||
|
// This is the recursive case - proceed to the next element.
|
||||||
|
}
|
||||||
|
Overlap::Disjoint => {
|
||||||
|
// We have proven the borrow disjoint - further
|
||||||
|
// projections will remain disjoint.
|
||||||
|
debug!("borrow_conflicts_with_place: disjoint");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if borrow_place.projection.len() > access_place.projection.len() {
|
||||||
|
for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
|
||||||
|
{
|
||||||
|
// Borrow path is longer than the access path. Examples:
|
||||||
|
//
|
||||||
|
// - borrow of `a.b.c`, access to `a.b`
|
||||||
|
//
|
||||||
|
// Here, we know that the borrow can access a part of
|
||||||
|
// our place. This is a conflict if that is a part our
|
||||||
|
// access cares about.
|
||||||
|
|
||||||
|
let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
|
||||||
|
let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
|
||||||
|
|
||||||
|
match (elem, &base_ty.sty, access) {
|
||||||
|
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
||||||
|
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
||||||
|
// The array length is like additional fields on the
|
||||||
|
// type; it does not overlap any existing data there.
|
||||||
|
// Furthermore, if cannot actually be a prefix of any
|
||||||
|
// borrowed place (at least in MIR as it is currently.)
|
||||||
|
//
|
||||||
|
// e.g., a (mutable) borrow of `a[5]` while we read the
|
||||||
|
// array length of `a`.
|
||||||
|
debug!("borrow_conflicts_with_place: implicit field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(ProjectionElem::Deref, _, Shallow(None)) => {
|
||||||
|
// e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
|
||||||
|
// prefix thereof - the shallow access can't touch anything behind
|
||||||
|
// the pointer.
|
||||||
|
debug!("borrow_conflicts_with_place: shallow access behind ptr");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
|
||||||
|
// Shouldn't be tracked
|
||||||
|
bug!("Tracking borrow behind shared reference.");
|
||||||
|
}
|
||||||
|
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
|
||||||
|
// Values behind a mutable reference are not access either by dropping a
|
||||||
|
// value, or by StorageDead
|
||||||
|
debug!("borrow_conflicts_with_place: drop access behind ptr");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
|
||||||
|
// Drop can read/write arbitrary projections, so places
|
||||||
|
// conflict regardless of further projections.
|
||||||
|
if def.has_dtor(tcx) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(ProjectionElem::Deref, _, Deep)
|
||||||
|
| (ProjectionElem::Deref, _, AccessDepth::Drop)
|
||||||
|
| (ProjectionElem::Field { .. }, _, _)
|
||||||
|
| (ProjectionElem::Index { .. }, _, _)
|
||||||
|
| (ProjectionElem::ConstantIndex { .. }, _, _)
|
||||||
|
| (ProjectionElem::Subslice { .. }, _, _)
|
||||||
|
| (ProjectionElem::Downcast { .. }, _, _) => {
|
||||||
|
// Recursive case. This can still be disjoint on a
|
||||||
|
// further iteration if this a shallow access and
|
||||||
|
// there's a deref later on, e.g., a borrow
|
||||||
|
// of `*x.y` while accessing `x`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borrow path ran out but access path may not
|
||||||
|
// have. Examples:
|
||||||
|
//
|
||||||
|
// - borrow of `a.b`, access to `a.b.c`
|
||||||
|
// - borrow of `a.b`, access to `a.b`
|
||||||
|
//
|
||||||
|
// In the first example, where we didn't run out of
|
||||||
|
// access, the borrow can access all of our place, so we
|
||||||
|
// have a conflict.
|
||||||
|
//
|
||||||
|
// If the second example, where we did, then we still know
|
||||||
|
// that the borrow can access a *part* of our place that
|
||||||
|
// our access cares about, so we still have a conflict.
|
||||||
|
if borrow_kind == BorrowKind::Shallow
|
||||||
|
&& borrow_place.projection.len() < access_place.projection.len()
|
||||||
|
{
|
||||||
|
debug!("borrow_conflicts_with_place: shallow borrow");
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given that the bases of `elem1` and `elem2` are always either equal
|
// Given that the bases of `elem1` and `elem2` are always either equal
|
||||||
|
|
@ -381,11 +386,12 @@ fn place_projection_conflict<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
pi1_base: &PlaceBase<'tcx>,
|
pi1_base: &PlaceBase<'tcx>,
|
||||||
pi1: &Projection<'tcx>,
|
pi1_proj_base: &[PlaceElem<'tcx>],
|
||||||
pi2: &Projection<'tcx>,
|
pi1_elem: &PlaceElem<'tcx>,
|
||||||
|
pi2_elem: &PlaceElem<'tcx>,
|
||||||
bias: PlaceConflictBias,
|
bias: PlaceConflictBias,
|
||||||
) -> Overlap {
|
) -> Overlap {
|
||||||
match (&pi1.elem, &pi2.elem) {
|
match (pi1_elem, pi2_elem) {
|
||||||
(ProjectionElem::Deref, ProjectionElem::Deref) => {
|
(ProjectionElem::Deref, ProjectionElem::Deref) => {
|
||||||
// derefs (e.g., `*x` vs. `*x`) - recur.
|
// derefs (e.g., `*x` vs. `*x`) - recur.
|
||||||
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
|
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
|
||||||
|
|
@ -397,7 +403,7 @@ fn place_projection_conflict<'tcx>(
|
||||||
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
|
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
|
||||||
Overlap::EqualOrDisjoint
|
Overlap::EqualOrDisjoint
|
||||||
} else {
|
} else {
|
||||||
let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty;
|
let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Adt(def, _) if def.is_union() => {
|
ty::Adt(def, _) if def.is_union() => {
|
||||||
// Different fields of a union, we are basically stuck.
|
// Different fields of a union, we are basically stuck.
|
||||||
|
|
@ -493,7 +499,7 @@ fn place_projection_conflict<'tcx>(
|
||||||
// element (like -1 in Python) and `min_length` the first.
|
// element (like -1 in Python) and `min_length` the first.
|
||||||
// Therefore, `min_length - offset_from_end` gives the minimal possible
|
// Therefore, `min_length - offset_from_end` gives the minimal possible
|
||||||
// offset from the beginning
|
// offset from the beginning
|
||||||
if *offset_from_begin >= min_length - offset_from_end {
|
if *offset_from_begin >= *min_length - *offset_from_end {
|
||||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
|
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
|
||||||
Overlap::EqualOrDisjoint
|
Overlap::EqualOrDisjoint
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -538,8 +544,8 @@ fn place_projection_conflict<'tcx>(
|
||||||
| (ProjectionElem::Subslice { .. }, _)
|
| (ProjectionElem::Subslice { .. }, _)
|
||||||
| (ProjectionElem::Downcast(..), _) => bug!(
|
| (ProjectionElem::Downcast(..), _) => bug!(
|
||||||
"mismatched projections in place_element_conflict: {:?} and {:?}",
|
"mismatched projections in place_element_conflict: {:?} and {:?}",
|
||||||
pi1,
|
pi1_elem,
|
||||||
pi2
|
pi2_elem
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,9 @@ pub trait IsPrefixOf<'cx, 'tcx> {
|
||||||
|
|
||||||
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
|
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
|
||||||
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
|
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
|
||||||
let mut cursor = other.projection;
|
self.base == other.base
|
||||||
loop {
|
&& self.projection.len() <= other.projection.len()
|
||||||
if self.projection == cursor {
|
&& self.projection == &other.projection[..self.projection.len()]
|
||||||
return self.base == other.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
match cursor {
|
|
||||||
None => return false,
|
|
||||||
Some(proj) => cursor = &proj.base,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,112 +73,113 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
||||||
// downcasts here, but may return a base of a downcast).
|
// downcasts here, but may return a base of a downcast).
|
||||||
|
|
||||||
'cursor: loop {
|
'cursor: loop {
|
||||||
let proj = match &cursor {
|
match &cursor {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(_),
|
base: PlaceBase::Local(_),
|
||||||
projection: None,
|
projection: [],
|
||||||
}
|
}
|
||||||
| // search yielded this leaf
|
| // search yielded this leaf
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Static(_),
|
base: PlaceBase::Static(_),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
self.next = None;
|
self.next = None;
|
||||||
return Some(cursor);
|
return Some(cursor);
|
||||||
}
|
}
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection: Some(proj),
|
projection: [proj_base @ .., elem],
|
||||||
} => proj,
|
} => {
|
||||||
};
|
match elem {
|
||||||
|
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
|
||||||
|
// FIXME: add union handling
|
||||||
|
self.next = Some(PlaceRef {
|
||||||
|
base: cursor.base,
|
||||||
|
projection: proj_base,
|
||||||
|
});
|
||||||
|
return Some(cursor);
|
||||||
|
}
|
||||||
|
ProjectionElem::Downcast(..) |
|
||||||
|
ProjectionElem::Subslice { .. } |
|
||||||
|
ProjectionElem::ConstantIndex { .. } |
|
||||||
|
ProjectionElem::Index(_) => {
|
||||||
|
cursor = PlaceRef {
|
||||||
|
base: cursor.base,
|
||||||
|
projection: proj_base,
|
||||||
|
};
|
||||||
|
continue 'cursor;
|
||||||
|
}
|
||||||
|
ProjectionElem::Deref => {
|
||||||
|
// (handled below)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match proj.elem {
|
assert_eq!(*elem, ProjectionElem::Deref);
|
||||||
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
|
|
||||||
// FIXME: add union handling
|
|
||||||
self.next = Some(PlaceRef {
|
|
||||||
base: cursor.base,
|
|
||||||
projection: &proj.base,
|
|
||||||
});
|
|
||||||
return Some(cursor);
|
|
||||||
}
|
|
||||||
ProjectionElem::Downcast(..) |
|
|
||||||
ProjectionElem::Subslice { .. } |
|
|
||||||
ProjectionElem::ConstantIndex { .. } |
|
|
||||||
ProjectionElem::Index(_) => {
|
|
||||||
cursor = PlaceRef {
|
|
||||||
base: cursor.base,
|
|
||||||
projection: &proj.base,
|
|
||||||
};
|
|
||||||
continue 'cursor;
|
|
||||||
}
|
|
||||||
ProjectionElem::Deref => {
|
|
||||||
// (handled below)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(proj.elem, ProjectionElem::Deref);
|
match self.kind {
|
||||||
|
PrefixSet::Shallow => {
|
||||||
|
// Shallow prefixes are found by stripping away
|
||||||
|
// fields, but stop at *any* dereference.
|
||||||
|
// So we can just stop the traversal now.
|
||||||
|
self.next = None;
|
||||||
|
return Some(cursor);
|
||||||
|
}
|
||||||
|
PrefixSet::All => {
|
||||||
|
// All prefixes: just blindly enqueue the base
|
||||||
|
// of the projection.
|
||||||
|
self.next = Some(PlaceRef {
|
||||||
|
base: cursor.base,
|
||||||
|
projection: proj_base,
|
||||||
|
});
|
||||||
|
return Some(cursor);
|
||||||
|
}
|
||||||
|
PrefixSet::Supporting => {
|
||||||
|
// Fall through!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.kind {
|
assert_eq!(self.kind, PrefixSet::Supporting);
|
||||||
PrefixSet::Shallow => {
|
// Supporting prefixes: strip away fields and
|
||||||
// shallow prefixes are found by stripping away
|
// derefs, except we stop at the deref of a shared
|
||||||
// fields, but stop at *any* dereference.
|
// reference.
|
||||||
// So we can just stop the traversal now.
|
|
||||||
self.next = None;
|
|
||||||
return Some(cursor);
|
|
||||||
}
|
|
||||||
PrefixSet::All => {
|
|
||||||
// all prefixes: just blindly enqueue the base
|
|
||||||
// of the projection.
|
|
||||||
self.next = Some(PlaceRef {
|
|
||||||
base: cursor.base,
|
|
||||||
projection: &proj.base,
|
|
||||||
});
|
|
||||||
return Some(cursor);
|
|
||||||
}
|
|
||||||
PrefixSet::Supporting => {
|
|
||||||
// fall through!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(self.kind, PrefixSet::Supporting);
|
let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty;
|
||||||
// supporting prefixes: strip away fields and
|
match ty.sty {
|
||||||
// derefs, except we stop at the deref of a shared
|
ty::RawPtr(_) |
|
||||||
// reference.
|
ty::Ref(
|
||||||
|
_, /*rgn*/
|
||||||
|
_, /*ty*/
|
||||||
|
hir::MutImmutable
|
||||||
|
) => {
|
||||||
|
// don't continue traversing over derefs of raw pointers or shared
|
||||||
|
// borrows.
|
||||||
|
self.next = None;
|
||||||
|
return Some(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
|
ty::Ref(
|
||||||
match ty.sty {
|
_, /*rgn*/
|
||||||
ty::RawPtr(_) |
|
_, /*ty*/
|
||||||
ty::Ref(
|
hir::MutMutable,
|
||||||
_, /*rgn*/
|
) => {
|
||||||
_, /*ty*/
|
self.next = Some(PlaceRef {
|
||||||
hir::MutImmutable
|
base: cursor.base,
|
||||||
) => {
|
projection: proj_base,
|
||||||
// don't continue traversing over derefs of raw pointers or shared borrows.
|
});
|
||||||
self.next = None;
|
return Some(cursor);
|
||||||
return Some(cursor);
|
}
|
||||||
|
|
||||||
|
ty::Adt(..) if ty.is_box() => {
|
||||||
|
self.next = Some(PlaceRef {
|
||||||
|
base: cursor.base,
|
||||||
|
projection: proj_base,
|
||||||
|
});
|
||||||
|
return Some(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => panic!("unknown type fed to Projection Deref."),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Ref(
|
|
||||||
_, /*rgn*/
|
|
||||||
_, /*ty*/
|
|
||||||
hir::MutMutable,
|
|
||||||
) => {
|
|
||||||
self.next = Some(PlaceRef {
|
|
||||||
base: cursor.base,
|
|
||||||
projection: &proj.base,
|
|
||||||
});
|
|
||||||
return Some(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Adt(..) if ty.is_box() => {
|
|
||||||
self.next = Some(PlaceRef {
|
|
||||||
base: cursor.base,
|
|
||||||
projection: &proj.base,
|
|
||||||
});
|
|
||||||
return Some(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => panic!("unknown type fed to Projection Deref."),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(into, _) => {
|
StatementKind::Assign(box(into, _)) => {
|
||||||
if let PlaceBase::Local(local) = into.base {
|
if let PlaceBase::Local(local) = into.base {
|
||||||
debug!(
|
debug!(
|
||||||
"visit_statement: statement={:?} local={:?} \
|
"visit_statement: statement={:?} local={:?} \
|
||||||
|
|
@ -120,7 +120,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
||||||
);
|
);
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(user_local),
|
base: PlaceBase::Local(user_local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = path.place {
|
} = path.place {
|
||||||
self.mbcx.used_mut.insert(user_local);
|
self.mbcx.used_mut.insert(user_local);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ impl<'tcx> CFG<'tcx> {
|
||||||
rvalue: Rvalue<'tcx>) {
|
rvalue: Rvalue<'tcx>) {
|
||||||
self.push(block, Statement {
|
self.push(block, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Assign(place.clone(), box rvalue)
|
kind: StatementKind::Assign(box(place.clone(), rvalue))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
kind: StaticKind::Static,
|
kind: StaticKind::Static,
|
||||||
def_id: id,
|
def_id: id,
|
||||||
})),
|
})),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
||||||
|
|
@ -147,9 +147,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::AscribeUserType(
|
kind: StatementKind::AscribeUserType(
|
||||||
place.clone(),
|
box(
|
||||||
|
place.clone(),
|
||||||
|
UserTypeProjection { base: annotation_index, projs: vec![], }
|
||||||
|
),
|
||||||
Variance::Invariant,
|
Variance::Invariant,
|
||||||
box UserTypeProjection { base: annotation_index, projs: vec![], },
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -174,9 +176,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::AscribeUserType(
|
kind: StatementKind::AscribeUserType(
|
||||||
Place::from(temp.clone()),
|
box(
|
||||||
|
Place::from(temp.clone()),
|
||||||
|
UserTypeProjection { base: annotation_index, projs: vec![], },
|
||||||
|
),
|
||||||
Variance::Invariant,
|
Variance::Invariant,
|
||||||
box UserTypeProjection { base: annotation_index, projs: vec![], },
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -500,14 +500,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let mutability = match arg_place {
|
let mutability = match arg_place {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} => this.local_decls[local].mutability,
|
} => this.local_decls[local].mutability,
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: Some(box Projection {
|
projection: box [ProjectionElem::Deref],
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
})
|
|
||||||
} => {
|
} => {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
this.local_decls[local].is_ref_for_guard(),
|
this.local_decls[local].is_ref_for_guard(),
|
||||||
|
|
@ -517,24 +514,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
Place {
|
Place {
|
||||||
ref base,
|
ref base,
|
||||||
projection: Some(box Projection {
|
projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||||
base: ref base_proj,
|
|
||||||
elem: ProjectionElem::Field(upvar_index, _),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
| Place {
|
| Place {
|
||||||
ref base,
|
ref base,
|
||||||
projection: Some(box Projection {
|
projection: box [
|
||||||
base: Some(box Projection {
|
ref proj_base @ ..,
|
||||||
base: ref base_proj,
|
ProjectionElem::Field(upvar_index, _),
|
||||||
elem: ProjectionElem::Field(upvar_index, _),
|
ProjectionElem::Deref
|
||||||
}),
|
],
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
}),
|
|
||||||
} => {
|
} => {
|
||||||
let place = PlaceRef {
|
let place = PlaceRef {
|
||||||
base,
|
base,
|
||||||
projection: base_proj,
|
projection: proj_base,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not projected from the implicit `self` in a closure.
|
// Not projected from the implicit `self` in a closure.
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Create a "fake" temporary variable so that we check that the
|
// Create a "fake" temporary variable so that we check that the
|
||||||
// value is Sized. Usually, this is caught in type checking, but
|
// value is Sized. Usually, this is caught in type checking, but
|
||||||
// in the case of box expr there is no such check.
|
// in the case of box expr there is no such check.
|
||||||
if destination.projection.is_some() {
|
if !destination.projection.is_empty() {
|
||||||
this.local_decls
|
this.local_decls
|
||||||
.push(LocalDecl::new_temp(expr.ty, expr.span));
|
.push(LocalDecl::new_temp(expr.ty, expr.span));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::FakeRead(
|
kind: StatementKind::FakeRead(
|
||||||
FakeReadCause::ForMatchedPlace,
|
FakeReadCause::ForMatchedPlace,
|
||||||
scrutinee_place.clone(),
|
box(scrutinee_place.clone()),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -320,7 +320,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block,
|
block,
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, place),
|
kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -362,12 +362,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
block,
|
block,
|
||||||
Statement {
|
Statement {
|
||||||
source_info: pattern_source_info,
|
source_info: pattern_source_info,
|
||||||
kind: StatementKind::FakeRead(FakeReadCause::ForLet, place.clone()),
|
kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let ty_source_info = self.source_info(user_ty_span);
|
let ty_source_info = self.source_info(user_ty_span);
|
||||||
let user_ty = box pat_ascription_ty.user_ty(
|
let user_ty = pat_ascription_ty.user_ty(
|
||||||
&mut self.canonical_user_type_annotations,
|
&mut self.canonical_user_type_annotations,
|
||||||
place.ty(&self.local_decls, self.hir.tcx()).ty,
|
place.ty(&self.local_decls, self.hir.tcx()).ty,
|
||||||
ty_source_info.span,
|
ty_source_info.span,
|
||||||
|
|
@ -377,7 +377,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Statement {
|
Statement {
|
||||||
source_info: ty_source_info,
|
source_info: ty_source_info,
|
||||||
kind: StatementKind::AscribeUserType(
|
kind: StatementKind::AscribeUserType(
|
||||||
place,
|
box(
|
||||||
|
place,
|
||||||
|
user_ty,
|
||||||
|
),
|
||||||
// We always use invariant as the variance here. This is because the
|
// We always use invariant as the variance here. This is because the
|
||||||
// variance field from the ascription refers to the variance to use
|
// variance field from the ascription refers to the variance to use
|
||||||
// when applying the type to the value being matched, but this
|
// when applying the type to the value being matched, but this
|
||||||
|
|
@ -393,7 +396,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// contrast, is intended to be used to relate `T` to the type of
|
// contrast, is intended to be used to relate `T` to the type of
|
||||||
// `<expr>`.
|
// `<expr>`.
|
||||||
ty::Variance::Invariant,
|
ty::Variance::Invariant,
|
||||||
user_ty,
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -942,16 +944,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
for Binding { source, .. }
|
for Binding { source, .. }
|
||||||
in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
|
in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
|
||||||
{
|
{
|
||||||
let mut cursor = &source.projection;
|
if let Some(i) =
|
||||||
while let Some(box Projection { base, elem }) = cursor {
|
source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
|
||||||
cursor = base;
|
{
|
||||||
if let ProjectionElem::Deref = elem {
|
let proj_base = &source.projection[..i];
|
||||||
fake_borrows.insert(Place {
|
|
||||||
base: source.base.clone(),
|
fake_borrows.insert(Place {
|
||||||
projection: cursor.clone(),
|
base: source.base.clone(),
|
||||||
});
|
projection: proj_base.to_vec().into_boxed_slice(),
|
||||||
break;
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1295,18 +1296,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
||||||
for place in fake_borrows
|
for place in fake_borrows
|
||||||
{
|
{
|
||||||
let mut prefix_cursor = &place.projection;
|
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||||
while let Some(box Projection { base, elem }) = prefix_cursor {
|
let proj_base = &place.projection[..i];
|
||||||
|
|
||||||
if let ProjectionElem::Deref = elem {
|
if let ProjectionElem::Deref = elem {
|
||||||
// Insert a shallow borrow after a deref. For other
|
// Insert a shallow borrow after a deref. For other
|
||||||
// projections the borrow of prefix_cursor will
|
// projections the borrow of prefix_cursor will
|
||||||
// conflict with any mutation of base.
|
// conflict with any mutation of base.
|
||||||
all_fake_borrows.push(PlaceRef {
|
all_fake_borrows.push(PlaceRef {
|
||||||
base: &place.base,
|
base: &place.base,
|
||||||
projection: base,
|
projection: proj_base,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
prefix_cursor = base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
all_fake_borrows.push(place.as_ref());
|
all_fake_borrows.push(place.as_ref());
|
||||||
|
|
@ -1489,7 +1490,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
BorrowKind::Shallow,
|
BorrowKind::Shallow,
|
||||||
Place {
|
Place {
|
||||||
base: place.base.clone(),
|
base: place.base.clone(),
|
||||||
projection: place.projection.clone(),
|
projection: place.projection.to_vec().into_boxed_slice(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.cfg.push_assign(
|
self.cfg.push_assign(
|
||||||
|
|
@ -1520,7 +1521,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
source_info: guard_end,
|
source_info: guard_end,
|
||||||
kind: StatementKind::FakeRead(
|
kind: StatementKind::FakeRead(
|
||||||
FakeReadCause::ForMatchGuard,
|
FakeReadCause::ForMatchGuard,
|
||||||
Place::from(temp),
|
box(Place::from(temp)),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1570,7 +1571,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
post_guard_block,
|
post_guard_block,
|
||||||
Statement {
|
Statement {
|
||||||
source_info: guard_end,
|
source_info: guard_end,
|
||||||
kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
|
kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1603,7 +1604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ascription.user_ty,
|
ascription.user_ty,
|
||||||
);
|
);
|
||||||
|
|
||||||
let user_ty = box ascription.user_ty.clone().user_ty(
|
let user_ty = ascription.user_ty.clone().user_ty(
|
||||||
&mut self.canonical_user_type_annotations,
|
&mut self.canonical_user_type_annotations,
|
||||||
ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
|
ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
|
||||||
source_info.span
|
source_info.span
|
||||||
|
|
@ -1613,9 +1614,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::AscribeUserType(
|
kind: StatementKind::AscribeUserType(
|
||||||
ascription.source.clone(),
|
box(
|
||||||
|
ascription.source.clone(),
|
||||||
|
user_ty,
|
||||||
|
),
|
||||||
ascription.variance,
|
ascription.variance,
|
||||||
user_ty,
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -609,7 +609,7 @@ where
|
||||||
unpack!(block = builder.in_breakable_scope(
|
unpack!(block = builder.in_breakable_scope(
|
||||||
None,
|
None,
|
||||||
START_BLOCK,
|
START_BLOCK,
|
||||||
Place::RETURN_PLACE,
|
Place::return_place(),
|
||||||
|builder| {
|
|builder| {
|
||||||
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||||
builder.args_and_body(block, &arguments, arg_scope, &body.value)
|
builder.args_and_body(block, &arguments, arg_scope, &body.value)
|
||||||
|
|
@ -670,7 +670,7 @@ fn construct_const<'a, 'tcx>(
|
||||||
let mut block = START_BLOCK;
|
let mut block = START_BLOCK;
|
||||||
let ast_expr = &tcx.hir().body(body_id).value;
|
let ast_expr = &tcx.hir().body(body_id).value;
|
||||||
let expr = builder.hir.mirror(ast_expr);
|
let expr = builder.hir.mirror(ast_expr);
|
||||||
unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr));
|
unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
|
||||||
|
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
||||||
|
|
@ -871,7 +871,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = self.hir.mirror(ast_body);
|
let body = self.hir.mirror(ast_body);
|
||||||
self.into(&Place::RETURN_PLACE, block, body)
|
self.into(&Place::return_place(), block, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_correct_source_scope_for_arg(
|
fn set_correct_source_scope_for_arg(
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,7 @@ impl<'tcx> Scopes<'tcx> {
|
||||||
match target {
|
match target {
|
||||||
BreakableTarget::Return => {
|
BreakableTarget::Return => {
|
||||||
let scope = &self.breakable_scopes[0];
|
let scope = &self.breakable_scopes[0];
|
||||||
if scope.break_destination != Place::RETURN_PLACE {
|
if scope.break_destination != Place::return_place() {
|
||||||
span_bug!(span, "`return` in item with no return scope");
|
span_bug!(span, "`return` in item with no return scope");
|
||||||
}
|
}
|
||||||
(scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
|
(scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
|
||||||
|
|
@ -853,11 +853,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
_ if self.local_scope().is_none() => (),
|
_ if self.local_scope().is_none() => (),
|
||||||
Operand::Copy(Place {
|
Operand::Copy(Place {
|
||||||
base: PlaceBase::Local(cond_temp),
|
base: PlaceBase::Local(cond_temp),
|
||||||
projection: None,
|
projection: box [],
|
||||||
})
|
})
|
||||||
| Operand::Move(Place {
|
| Operand::Move(Place {
|
||||||
base: PlaceBase::Local(cond_temp),
|
base: PlaceBase::Local(cond_temp),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) => {
|
}) => {
|
||||||
// Manually drop the condition on both branches.
|
// Manually drop the condition on both branches.
|
||||||
let top_scope = self.scopes.scopes.last_mut().unwrap();
|
let top_scope = self.scopes.scopes.last_mut().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -10,19 +10,17 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
|
||||||
path: MovePathIndex,
|
path: MovePathIndex,
|
||||||
mut cond: F)
|
mut cond: F)
|
||||||
-> Option<MovePathIndex>
|
-> Option<MovePathIndex>
|
||||||
where F: FnMut(&mir::Projection<'tcx>) -> bool
|
where F: FnMut(&mir::PlaceElem<'tcx>) -> bool
|
||||||
{
|
{
|
||||||
let mut next_child = move_data.move_paths[path].first_child;
|
let mut next_child = move_data.move_paths[path].first_child;
|
||||||
while let Some(child_index) = next_child {
|
while let Some(child_index) = next_child {
|
||||||
match move_data.move_paths[child_index].place.projection {
|
let move_path_children = &move_data.move_paths[child_index];
|
||||||
Some(ref proj) => {
|
if let Some(elem) = move_path_children.place.projection.last() {
|
||||||
if cond(proj) {
|
if cond(elem) {
|
||||||
return Some(child_index)
|
return Some(child_index)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
next_child = move_data.move_paths[child_index].next_sibling;
|
next_child = move_path_children.next_sibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
||||||
// If the borrowed place is a local with no projections, all other borrows of this
|
// If the borrowed place is a local with no projections, all other borrows of this
|
||||||
// local must conflict. This is purely an optimization so we don't have to call
|
// local must conflict. This is purely an optimization so we don't have to call
|
||||||
// `places_conflict` for every borrow.
|
// `places_conflict` for every borrow.
|
||||||
if place.projection.is_none() {
|
if place.projection.is_empty() {
|
||||||
trans.kill_all(other_borrows_of_local);
|
trans.kill_all(other_borrows_of_local);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -268,8 +268,8 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
|
||||||
|
|
||||||
debug!("Borrows::statement_effect: stmt={:?}", stmt);
|
debug!("Borrows::statement_effect: stmt={:?}", stmt);
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
mir::StatementKind::Assign(ref lhs, ref rhs) => {
|
mir::StatementKind::Assign(box(ref lhs, ref rhs)) => {
|
||||||
if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
|
if let mir::Rvalue::Ref(_, _, ref place) = *rhs {
|
||||||
if place.ignore_borrow(
|
if place.ignore_borrow(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
self.body,
|
self.body,
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::StorageLive(l) => sets.gen(l),
|
StatementKind::StorageLive(l) => sets.gen(l),
|
||||||
StatementKind::StorageDead(l) => sets.kill(l),
|
StatementKind::StorageDead(l) => sets.kill(l),
|
||||||
StatementKind::Assign(ref place, _)
|
StatementKind::Assign(box(ref place, _))
|
||||||
| StatementKind::SetDiscriminant { ref place, .. } => {
|
| StatementKind::SetDiscriminant { box ref place, .. } => {
|
||||||
if let PlaceBase::Local(local) = place.base {
|
if let PlaceBase::Local(local) = place.base {
|
||||||
sets.gen(local);
|
sets.gen(local);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,72 +94,74 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
||||||
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
||||||
debug!("lookup({:?})", place);
|
debug!("lookup({:?})", place);
|
||||||
place.iterate(|place_base, place_projection| {
|
let mut base = match place.base {
|
||||||
let mut base = match place_base {
|
PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
|
||||||
PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[*local],
|
PlaceBase::Static(..) => {
|
||||||
PlaceBase::Static(..) => {
|
return Err(MoveError::cannot_move_out_of(self.loc, Static));
|
||||||
return Err(MoveError::cannot_move_out_of(self.loc, Static));
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i, elem) in place.projection.iter().enumerate() {
|
||||||
|
let proj_base = &place.projection[..i];
|
||||||
|
let body = self.builder.body;
|
||||||
|
let tcx = self.builder.tcx;
|
||||||
|
let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty;
|
||||||
|
match place_ty.sty {
|
||||||
|
ty::Ref(..) | ty::RawPtr(..) => {
|
||||||
|
let proj = &place.projection[..i+1];
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
BorrowedContent {
|
||||||
|
target_place: Place {
|
||||||
|
base: place.base.clone(),
|
||||||
|
projection: proj.to_vec().into_boxed_slice(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// move out of union - always move the entire union
|
||||||
|
ty::Adt(adt, _) if adt.is_union() => {
|
||||||
|
return Err(MoveError::UnionMove { path: base });
|
||||||
|
}
|
||||||
|
ty::Slice(_) => {
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
InteriorOfSliceOrArray {
|
||||||
|
ty: place_ty,
|
||||||
|
is_index: match elem {
|
||||||
|
ProjectionElem::Index(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
ty::Array(..) => match elem {
|
||||||
|
ProjectionElem::Index(..) => {
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// FIXME: still badly broken
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
for proj in place_projection {
|
let proj = &place.projection[..i+1];
|
||||||
let body = self.builder.body;
|
base = match self
|
||||||
let tcx = self.builder.tcx;
|
.builder
|
||||||
let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
|
.data
|
||||||
match place_ty.sty {
|
.rev_lookup
|
||||||
ty::Ref(..) | ty::RawPtr(..) => {
|
.projections
|
||||||
return Err(MoveError::cannot_move_out_of(
|
.entry((base, elem.lift()))
|
||||||
self.loc,
|
|
||||||
BorrowedContent {
|
|
||||||
target_place: Place {
|
|
||||||
base: place_base.clone(),
|
|
||||||
projection: Some(Box::new(proj.clone())),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
|
|
||||||
return Err(MoveError::cannot_move_out_of(
|
|
||||||
self.loc,
|
|
||||||
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
|
||||||
));
|
|
||||||
}
|
|
||||||
// move out of union - always move the entire union
|
|
||||||
ty::Adt(adt, _) if adt.is_union() => {
|
|
||||||
return Err(MoveError::UnionMove { path: base });
|
|
||||||
}
|
|
||||||
ty::Slice(_) => {
|
|
||||||
return Err(MoveError::cannot_move_out_of(
|
|
||||||
self.loc,
|
|
||||||
InteriorOfSliceOrArray {
|
|
||||||
ty: place_ty,
|
|
||||||
is_index: match proj.elem {
|
|
||||||
ProjectionElem::Index(..) => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
ty::Array(..) => match proj.elem {
|
|
||||||
ProjectionElem::Index(..) => {
|
|
||||||
return Err(MoveError::cannot_move_out_of(
|
|
||||||
self.loc,
|
|
||||||
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// FIXME: still badly broken
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
base = match self
|
|
||||||
.builder
|
|
||||||
.data
|
|
||||||
.rev_lookup
|
|
||||||
.projections
|
|
||||||
.entry((base, proj.elem.lift()))
|
|
||||||
{
|
{
|
||||||
Entry::Occupied(ent) => *ent.get(),
|
Entry::Occupied(ent) => *ent.get(),
|
||||||
Entry::Vacant(ent) => {
|
Entry::Vacant(ent) => {
|
||||||
|
|
@ -169,18 +171,17 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
&mut self.builder.data.init_path_map,
|
&mut self.builder.data.init_path_map,
|
||||||
Some(base),
|
Some(base),
|
||||||
Place {
|
Place {
|
||||||
base: place_base.clone(),
|
base: place.base.clone(),
|
||||||
projection: Some(Box::new(proj.clone())),
|
projection: proj.to_vec().into_boxed_slice(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ent.insert(path);
|
ent.insert(path);
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(base)
|
Ok(base)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_move_path(&mut self, place: &Place<'tcx>) {
|
fn create_move_path(&mut self, place: &Place<'tcx>) {
|
||||||
|
|
@ -267,7 +268,7 @@ struct Gatherer<'b, 'a, 'tcx> {
|
||||||
impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::Assign(ref place, ref rval) => {
|
StatementKind::Assign(box(ref place, ref rval)) => {
|
||||||
self.create_move_path(place);
|
self.create_move_path(place);
|
||||||
if let RvalueInitializationState::Shallow = rval.initialization_state() {
|
if let RvalueInitializationState::Shallow = rval.initialization_state() {
|
||||||
// Box starts out uninitialized - need to create a separate
|
// Box starts out uninitialized - need to create a separate
|
||||||
|
|
@ -355,7 +356,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
| TerminatorKind::Unreachable => {}
|
| TerminatorKind::Unreachable => {}
|
||||||
|
|
||||||
TerminatorKind::Return => {
|
TerminatorKind::Return => {
|
||||||
self.gather_move(&Place::RETURN_PLACE);
|
self.gather_move(&Place::return_place());
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Assert { ref cond, .. } => {
|
TerminatorKind::Assert { ref cond, .. } => {
|
||||||
|
|
@ -435,9 +436,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
|
|
||||||
// Check if we are assigning into a field of a union, if so, lookup the place
|
// Check if we are assigning into a field of a union, if so, lookup the place
|
||||||
// of the union so it is marked as initialized again.
|
// of the union so it is marked as initialized again.
|
||||||
if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) =
|
if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
|
||||||
place.projection
|
|
||||||
{
|
|
||||||
if let ty::Adt(def, _) =
|
if let ty::Adt(def, _) =
|
||||||
Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
|
Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -245,23 +245,21 @@ impl MovePathLookup {
|
||||||
// alternative will *not* create a MovePath on the fly for an
|
// alternative will *not* create a MovePath on the fly for an
|
||||||
// unknown place, but will rather return the nearest available
|
// unknown place, but will rather return the nearest available
|
||||||
// parent.
|
// parent.
|
||||||
pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult {
|
pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
|
||||||
place_ref.iterate(|place_base, place_projection| {
|
let mut result = match place.base {
|
||||||
let mut result = match place_base {
|
PlaceBase::Local(local) => self.locals[*local],
|
||||||
PlaceBase::Local(local) => self.locals[*local],
|
PlaceBase::Static(..) => return LookupResult::Parent(None),
|
||||||
PlaceBase::Static(..) => return LookupResult::Parent(None),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
for proj in place_projection {
|
for elem in place.projection.iter() {
|
||||||
if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
|
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
|
||||||
result = subpath;
|
result = subpath;
|
||||||
} else {
|
} else {
|
||||||
return LookupResult::Parent(Some(result));
|
return LookupResult::Parent(Some(result));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LookupResult::Exact(result)
|
LookupResult::Exact(result)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_local(&self, local: Local) -> MovePathIndex {
|
pub fn find_local(&self, local: Local) -> MovePathIndex {
|
||||||
|
|
@ -329,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
|
||||||
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
|
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
|
||||||
loop {
|
loop {
|
||||||
let path = &self.move_paths[mpi];
|
let path = &self.move_paths[mpi];
|
||||||
if let Place { base: PlaceBase::Local(l), projection: None } = path.place {
|
if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
|
||||||
return Some(l);
|
return Some(l);
|
||||||
}
|
}
|
||||||
if let Some(parent) = path.parent {
|
if let Some(parent) = path.parent {
|
||||||
|
|
|
||||||
|
|
@ -472,39 +472,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// avoid allocations.
|
// avoid allocations.
|
||||||
pub(super) fn eval_place_to_op(
|
pub(super) fn eval_place_to_op(
|
||||||
&self,
|
&self,
|
||||||
mir_place: &mir::Place<'tcx>,
|
place: &mir::Place<'tcx>,
|
||||||
layout: Option<TyLayout<'tcx>>,
|
layout: Option<TyLayout<'tcx>>,
|
||||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||||
use rustc::mir::PlaceBase;
|
use rustc::mir::PlaceBase;
|
||||||
|
|
||||||
mir_place.iterate(|place_base, place_projection| {
|
let mut op = match &place.base {
|
||||||
let mut op = match place_base {
|
PlaceBase::Local(mir::RETURN_PLACE) =>
|
||||||
PlaceBase::Local(mir::RETURN_PLACE) =>
|
throw_unsup!(ReadFromReturnPointer),
|
||||||
throw_unsup!(ReadFromReturnPointer),
|
PlaceBase::Local(local) => {
|
||||||
PlaceBase::Local(local) => {
|
// Do not use the layout passed in as argument if the base we are looking at
|
||||||
// Do not use the layout passed in as argument if the base we are looking at
|
// here is not the entire place.
|
||||||
// here is not the entire place.
|
// FIXME use place_projection.is_empty() when is available
|
||||||
// FIXME use place_projection.is_empty() when is available
|
let layout = if place.projection.is_empty() {
|
||||||
let layout = if mir_place.projection.is_none() {
|
layout
|
||||||
layout
|
} else {
|
||||||
} else {
|
None
|
||||||
None
|
};
|
||||||
};
|
|
||||||
|
|
||||||
self.access_local(self.frame(), *local, layout)?
|
self.access_local(self.frame(), *local, layout)?
|
||||||
}
|
|
||||||
PlaceBase::Static(place_static) => {
|
|
||||||
self.eval_static_to_mplace(place_static)?.into()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for proj in place_projection {
|
|
||||||
op = self.operand_projection(op, &proj.elem)?
|
|
||||||
}
|
}
|
||||||
|
PlaceBase::Static(place_static) => {
|
||||||
|
self.eval_static_to_mplace(&place_static)?.into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
trace!("eval_place_to_op: got {:?}", *op);
|
for elem in place.projection.iter() {
|
||||||
Ok(op)
|
op = self.operand_projection(op, elem)?
|
||||||
})
|
}
|
||||||
|
|
||||||
|
trace!("eval_place_to_op: got {:?}", *op);
|
||||||
|
Ok(op)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the operand, returning a place where you can then find the data.
|
/// Evaluate the operand, returning a place where you can then find the data.
|
||||||
|
|
|
||||||
|
|
@ -629,45 +629,43 @@ where
|
||||||
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
|
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
|
||||||
pub fn eval_place(
|
pub fn eval_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
mir_place: &mir::Place<'tcx>,
|
place: &mir::Place<'tcx>,
|
||||||
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
|
||||||
use rustc::mir::PlaceBase;
|
use rustc::mir::PlaceBase;
|
||||||
|
|
||||||
mir_place.iterate(|place_base, place_projection| {
|
let mut place_ty = match &place.base {
|
||||||
let mut place = match place_base {
|
PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
|
||||||
PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
|
Some(return_place) => {
|
||||||
Some(return_place) => {
|
// We use our layout to verify our assumption; caller will validate
|
||||||
// We use our layout to verify our assumption; caller will validate
|
// their layout on return.
|
||||||
// their layout on return.
|
PlaceTy {
|
||||||
PlaceTy {
|
place: *return_place,
|
||||||
place: *return_place,
|
layout: self.layout_of(
|
||||||
layout: self.layout_of(
|
self.subst_from_frame_and_normalize_erasing_regions(
|
||||||
self.subst_from_frame_and_normalize_erasing_regions(
|
self.frame().body.return_ty()
|
||||||
self.frame().body.return_ty()
|
)
|
||||||
)
|
)?,
|
||||||
)?,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => throw_unsup!(InvalidNullPointerUsage),
|
}
|
||||||
|
None => throw_unsup!(InvalidNullPointerUsage),
|
||||||
|
},
|
||||||
|
PlaceBase::Local(local) => PlaceTy {
|
||||||
|
// This works even for dead/uninitialized locals; we check further when writing
|
||||||
|
place: Place::Local {
|
||||||
|
frame: self.cur_frame(),
|
||||||
|
local: *local,
|
||||||
},
|
},
|
||||||
PlaceBase::Local(local) => PlaceTy {
|
layout: self.layout_of_local(self.frame(), *local, None)?,
|
||||||
// This works even for dead/uninitialized locals; we check further when writing
|
},
|
||||||
place: Place::Local {
|
PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
|
||||||
frame: self.cur_frame(),
|
};
|
||||||
local: *local,
|
|
||||||
},
|
|
||||||
layout: self.layout_of_local(self.frame(), *local, None)?,
|
|
||||||
},
|
|
||||||
PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
for proj in place_projection {
|
for elem in place.projection.iter() {
|
||||||
place = self.place_projection(place, &proj.elem)?
|
place_ty = self.place_projection(place_ty, elem)?
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dump_place(place.place);
|
self.dump_place(place_ty.place);
|
||||||
Ok(place)
|
Ok(place_ty)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a scalar to a place
|
/// Write a scalar to a place
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.memory.tcx.span = stmt.source_info.span;
|
self.memory.tcx.span = stmt.source_info.span;
|
||||||
|
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?,
|
Assign(box(ref place, ref rvalue)) => self.eval_rvalue_into_place(rvalue, place)?,
|
||||||
|
|
||||||
SetDiscriminant {
|
SetDiscriminant {
|
||||||
ref place,
|
ref place,
|
||||||
|
|
|
||||||
|
|
@ -391,7 +391,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// Don't forget to check the return type!
|
// Don't forget to check the return type!
|
||||||
if let Some(caller_ret) = dest {
|
if let Some(caller_ret) = dest {
|
||||||
let callee_ret = self.eval_place(
|
let callee_ret = self.eval_place(
|
||||||
&mir::Place::RETURN_PLACE
|
&mir::Place::return_place()
|
||||||
)?;
|
)?;
|
||||||
if !Self::check_argument_compat(
|
if !Self::check_argument_compat(
|
||||||
rust_abi,
|
rust_abi,
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
|
||||||
// Function arguments should be retagged, and we make this one raw.
|
// Function arguments should be retagged, and we make this one raw.
|
||||||
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
|
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Retag(RetagKind::Raw, dropee_ptr.clone()),
|
kind: StatementKind::Retag(RetagKind::Raw, box(dropee_ptr.clone())),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let patch = {
|
let patch = {
|
||||||
|
|
@ -308,7 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
|
||||||
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
|
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
|
||||||
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
|
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
|
||||||
|
|
||||||
let dest = Place::RETURN_PLACE;
|
let dest = Place::return_place();
|
||||||
let src = Place::from(Local::new(1+0)).deref();
|
let src = Place::from(Local::new(1+0)).deref();
|
||||||
|
|
||||||
match self_ty.sty {
|
match self_ty.sty {
|
||||||
|
|
@ -415,8 +415,10 @@ impl CloneShimBuilder<'tcx> {
|
||||||
let rcvr = Place::from(Local::new(1+0)).deref();
|
let rcvr = Place::from(Local::new(1+0)).deref();
|
||||||
let ret_statement = self.make_statement(
|
let ret_statement = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place::RETURN_PLACE,
|
box(
|
||||||
box Rvalue::Use(Operand::Copy(rcvr))
|
Place::return_place(),
|
||||||
|
Rvalue::Use(Operand::Copy(rcvr))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||||
|
|
@ -458,8 +460,10 @@ impl CloneShimBuilder<'tcx> {
|
||||||
// `let ref_loc: &ty = &src;`
|
// `let ref_loc: &ty = &src;`
|
||||||
let statement = self.make_statement(
|
let statement = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
ref_loc.clone(),
|
box(
|
||||||
box Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
|
ref_loc.clone(),
|
||||||
|
Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -486,8 +490,10 @@ impl CloneShimBuilder<'tcx> {
|
||||||
let cond = self.make_place(Mutability::Mut, tcx.types.bool);
|
let cond = self.make_place(Mutability::Mut, tcx.types.bool);
|
||||||
let compute_cond = self.make_statement(
|
let compute_cond = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
cond.clone(),
|
box(
|
||||||
box Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
cond.clone(),
|
||||||
|
Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -521,14 +527,18 @@ impl CloneShimBuilder<'tcx> {
|
||||||
let inits = vec![
|
let inits = vec![
|
||||||
self.make_statement(
|
self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place::from(beg),
|
box(
|
||||||
box Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
Place::from(beg),
|
||||||
|
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
self.make_statement(
|
self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
end.clone(),
|
box(
|
||||||
box Rvalue::Use(Operand::Constant(self.make_usize(len)))
|
end.clone(),
|
||||||
|
Rvalue::Use(Operand::Constant(self.make_usize(len)))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
@ -559,11 +569,13 @@ impl CloneShimBuilder<'tcx> {
|
||||||
let statements = vec![
|
let statements = vec![
|
||||||
self.make_statement(
|
self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place::from(beg),
|
box(
|
||||||
box Rvalue::BinaryOp(
|
Place::from(beg),
|
||||||
BinOp::Add,
|
Rvalue::BinaryOp(
|
||||||
Operand::Copy(Place::from(beg)),
|
BinOp::Add,
|
||||||
Operand::Constant(self.make_usize(1))
|
Operand::Copy(Place::from(beg)),
|
||||||
|
Operand::Constant(self.make_usize(1))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -582,8 +594,10 @@ impl CloneShimBuilder<'tcx> {
|
||||||
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
|
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
|
||||||
let init = self.make_statement(
|
let init = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place::from(beg),
|
box(
|
||||||
box Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
Place::from(beg),
|
||||||
|
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
|
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
|
||||||
|
|
@ -609,11 +623,13 @@ impl CloneShimBuilder<'tcx> {
|
||||||
// `goto #6;`
|
// `goto #6;`
|
||||||
let statement = self.make_statement(
|
let statement = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place::from(beg),
|
box(
|
||||||
box Rvalue::BinaryOp(
|
Place::from(beg),
|
||||||
BinOp::Add,
|
Rvalue::BinaryOp(
|
||||||
Operand::Copy(Place::from(beg)),
|
BinOp::Add,
|
||||||
Operand::Constant(self.make_usize(1))
|
Operand::Copy(Place::from(beg)),
|
||||||
|
Operand::Constant(self.make_usize(1))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
@ -727,8 +743,10 @@ fn build_call_shim<'tcx>(
|
||||||
statements.push(Statement {
|
statements.push(Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Assign(
|
kind: StatementKind::Assign(
|
||||||
Place::from(ref_rcvr),
|
box(
|
||||||
box Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
|
Place::from(ref_rcvr),
|
||||||
|
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
Operand::Move(Place::from(ref_rcvr))
|
Operand::Move(Place::from(ref_rcvr))
|
||||||
|
|
@ -773,7 +791,7 @@ fn build_call_shim<'tcx>(
|
||||||
block(&mut blocks, statements, TerminatorKind::Call {
|
block(&mut blocks, statements, TerminatorKind::Call {
|
||||||
func: callee,
|
func: callee,
|
||||||
args,
|
args,
|
||||||
destination: Some((Place::RETURN_PLACE,
|
destination: Some((Place::return_place(),
|
||||||
BasicBlock::new(1))),
|
BasicBlock::new(1))),
|
||||||
cleanup: if let Adjustment::RefMut = rcvr_adjustment {
|
cleanup: if let Adjustment::RefMut = rcvr_adjustment {
|
||||||
Some(BasicBlock::new(3))
|
Some(BasicBlock::new(3))
|
||||||
|
|
@ -868,7 +886,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
|
||||||
debug!("build_ctor: variant_index={:?}", variant_index);
|
debug!("build_ctor: variant_index={:?}", variant_index);
|
||||||
|
|
||||||
let statements = expand_aggregate(
|
let statements = expand_aggregate(
|
||||||
Place::RETURN_PLACE,
|
Place::return_place(),
|
||||||
adt_def
|
adt_def
|
||||||
.variants[variant_index]
|
.variants[variant_index]
|
||||||
.fields
|
.fields
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,11 @@ pub struct AddRetag;
|
||||||
fn is_stable(
|
fn is_stable(
|
||||||
place: PlaceRef<'_, '_>,
|
place: PlaceRef<'_, '_>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(proj) = &place.projection {
|
place.projection.iter().all(|elem| {
|
||||||
match proj.elem {
|
match elem {
|
||||||
// Which place this evaluates to can change with any memory write,
|
// Which place this evaluates to can change with any memory write,
|
||||||
// so cannot assume this to be stable.
|
// so cannot assume this to be stable.
|
||||||
ProjectionElem::Deref =>
|
ProjectionElem::Deref => false,
|
||||||
false,
|
|
||||||
// Array indices are intersting, but MIR building generates a *fresh*
|
// Array indices are intersting, but MIR building generates a *fresh*
|
||||||
// temporary for every array access, so the index cannot be changed as
|
// temporary for every array access, so the index cannot be changed as
|
||||||
// a side-effect.
|
// a side-effect.
|
||||||
|
|
@ -31,15 +30,9 @@ fn is_stable(
|
||||||
ProjectionElem::Field { .. } |
|
ProjectionElem::Field { .. } |
|
||||||
ProjectionElem::ConstantIndex { .. } |
|
ProjectionElem::ConstantIndex { .. } |
|
||||||
ProjectionElem::Subslice { .. } |
|
ProjectionElem::Subslice { .. } |
|
||||||
ProjectionElem::Downcast { .. } =>
|
ProjectionElem::Downcast { .. } => true,
|
||||||
is_stable(PlaceRef {
|
|
||||||
base: place.base,
|
|
||||||
projection: &proj.base,
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether this type may be a reference (or box), and thus needs retagging.
|
/// Determine whether this type may be a reference (or box), and thus needs retagging.
|
||||||
|
|
@ -96,7 +89,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||||
basic_blocks[START_BLOCK].statements.splice(0..0,
|
basic_blocks[START_BLOCK].statements.splice(0..0,
|
||||||
places.into_iter().map(|place| Statement {
|
places.into_iter().map(|place| Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Retag(RetagKind::FnEntry, place),
|
kind: StatementKind::Retag(RetagKind::FnEntry, box(place)),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +125,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||||
for (source_info, dest_place, dest_block) in returns {
|
for (source_info, dest_place, dest_block) in returns {
|
||||||
basic_blocks[dest_block].statements.insert(0, Statement {
|
basic_blocks[dest_block].statements.insert(0, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Retag(RetagKind::Default, dest_place),
|
kind: StatementKind::Retag(RetagKind::Default, box(dest_place)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,11 +137,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||||
for i in (0..block_data.statements.len()).rev() {
|
for i in (0..block_data.statements.len()).rev() {
|
||||||
let (retag_kind, place) = match block_data.statements[i].kind {
|
let (retag_kind, place) = match block_data.statements[i].kind {
|
||||||
// If we are casting *from* a reference, we may have to retag-as-raw.
|
// If we are casting *from* a reference, we may have to retag-as-raw.
|
||||||
StatementKind::Assign(ref place, box Rvalue::Cast(
|
StatementKind::Assign(box(ref place, Rvalue::Cast(
|
||||||
CastKind::Misc,
|
CastKind::Misc,
|
||||||
ref src,
|
ref src,
|
||||||
dest_ty,
|
dest_ty,
|
||||||
)) => {
|
))) => {
|
||||||
let src_ty = src.ty(&*local_decls, tcx);
|
let src_ty = src.ty(&*local_decls, tcx);
|
||||||
if src_ty.is_region_ptr() {
|
if src_ty.is_region_ptr() {
|
||||||
// The only `Misc` casts on references are those creating raw pointers.
|
// The only `Misc` casts on references are those creating raw pointers.
|
||||||
|
|
@ -162,7 +155,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||||
// Assignments of reference or ptr type are the ones where we may have
|
// Assignments of reference or ptr type are the ones where we may have
|
||||||
// to update tags. This includes `x = &[mut] ...` and hence
|
// to update tags. This includes `x = &[mut] ...` and hence
|
||||||
// we also retag after taking a reference!
|
// we also retag after taking a reference!
|
||||||
StatementKind::Assign(ref place, box ref rvalue) if needs_retag(place) => {
|
StatementKind::Assign(box(ref place, ref rvalue)) if needs_retag(place) => {
|
||||||
let kind = match rvalue {
|
let kind = match rvalue {
|
||||||
Rvalue::Ref(_, borrow_kind, _)
|
Rvalue::Ref(_, borrow_kind, _)
|
||||||
if borrow_kind.allows_two_phase_borrow()
|
if borrow_kind.allows_two_phase_borrow()
|
||||||
|
|
@ -180,7 +173,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||||
let source_info = block_data.statements[i].source_info;
|
let source_info = block_data.statements[i].source_info;
|
||||||
block_data.statements.insert(i+1, Statement {
|
block_data.statements.insert(i+1, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Retag(retag_kind, place),
|
kind: StatementKind::Retag(retag_kind, box(place)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -200,127 +200,127 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
_location: Location) {
|
_location: Location) {
|
||||||
place.iterate(|place_base, place_projections| {
|
match place.base {
|
||||||
match place_base {
|
PlaceBase::Local(..) => {
|
||||||
PlaceBase::Local(..) => {
|
// Locals are safe.
|
||||||
// Locals are safe.
|
}
|
||||||
}
|
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
|
||||||
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
|
bug!("unsafety checking should happen before promotion")
|
||||||
bug!("unsafety checking should happen before promotion")
|
}
|
||||||
}
|
PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
|
||||||
PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
|
if self.tcx.is_mutable_static(def_id) {
|
||||||
if self.tcx.is_mutable_static(*def_id) {
|
self.require_unsafe("use of mutable static",
|
||||||
self.require_unsafe("use of mutable static",
|
"mutable statics can be mutated by multiple threads: aliasing \
|
||||||
"mutable statics can be mutated by multiple threads: aliasing \
|
violations or data races will cause undefined behavior",
|
||||||
violations or data races will cause undefined behavior",
|
UnsafetyViolationKind::General);
|
||||||
UnsafetyViolationKind::General);
|
} else if self.tcx.is_foreign_item(def_id) {
|
||||||
} else if self.tcx.is_foreign_item(*def_id) {
|
let source_info = self.source_info;
|
||||||
let source_info = self.source_info;
|
let lint_root =
|
||||||
let lint_root =
|
self.source_scope_local_data[source_info.scope].lint_root;
|
||||||
self.source_scope_local_data[source_info.scope].lint_root;
|
self.register_violations(&[UnsafetyViolation {
|
||||||
self.register_violations(&[UnsafetyViolation {
|
source_info,
|
||||||
source_info,
|
description: InternedString::intern("use of extern static"),
|
||||||
description: InternedString::intern("use of extern static"),
|
details: InternedString::intern(
|
||||||
details: InternedString::intern(
|
"extern statics are not controlled by the Rust type system: \
|
||||||
"extern statics are not controlled by the Rust type system: \
|
invalid data, aliasing violations or data races will cause \
|
||||||
invalid data, aliasing violations or data races will cause \
|
undefined behavior"),
|
||||||
undefined behavior"),
|
kind: UnsafetyViolationKind::ExternStatic(lint_root)
|
||||||
kind: UnsafetyViolationKind::ExternStatic(lint_root)
|
}], &[]);
|
||||||
}], &[]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for proj in place_projections {
|
for (i, elem) in place.projection.iter().enumerate() {
|
||||||
if context.is_borrow() {
|
let proj_base = &place.projection[..i];
|
||||||
if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
|
|
||||||
let source_info = self.source_info;
|
if context.is_borrow() {
|
||||||
let lint_root =
|
if util::is_disaligned(self.tcx, self.body, self.param_env, place) {
|
||||||
self.source_scope_local_data[source_info.scope].lint_root;
|
let source_info = self.source_info;
|
||||||
self.register_violations(&[UnsafetyViolation {
|
let lint_root =
|
||||||
source_info,
|
self.source_scope_local_data[source_info.scope].lint_root;
|
||||||
description: InternedString::intern("borrow of packed field"),
|
self.register_violations(&[UnsafetyViolation {
|
||||||
details: InternedString::intern(
|
source_info,
|
||||||
"fields of packed structs might be misaligned: dereferencing a \
|
description: InternedString::intern("borrow of packed field"),
|
||||||
misaligned pointer or even just creating a misaligned reference \
|
details: InternedString::intern(
|
||||||
is undefined behavior"),
|
"fields of packed structs might be misaligned: dereferencing a \
|
||||||
kind: UnsafetyViolationKind::BorrowPacked(lint_root)
|
misaligned pointer or even just creating a misaligned reference \
|
||||||
}], &[]);
|
is undefined behavior"),
|
||||||
}
|
kind: UnsafetyViolationKind::BorrowPacked(lint_root)
|
||||||
|
}], &[]);
|
||||||
}
|
}
|
||||||
let is_borrow_of_interior_mut = context.is_borrow() &&
|
}
|
||||||
!Place::ty_from(&place.base, &proj.base, self.body, self.tcx)
|
let is_borrow_of_interior_mut = context.is_borrow() &&
|
||||||
.ty
|
!Place::ty_from(&place.base, proj_base, self.body, self.tcx)
|
||||||
.is_freeze(self.tcx, self.param_env, self.source_info.span);
|
.ty
|
||||||
// prevent
|
.is_freeze(self.tcx, self.param_env, self.source_info.span);
|
||||||
// * `&mut x.field`
|
// prevent
|
||||||
// * `x.field = y;`
|
// * `&mut x.field`
|
||||||
// * `&x.field` if `field`'s type has interior mutability
|
// * `x.field = y;`
|
||||||
// because either of these would allow modifying the layout constrained field and
|
// * `&x.field` if `field`'s type has interior mutability
|
||||||
// insert values that violate the layout constraints.
|
// because either of these would allow modifying the layout constrained field and
|
||||||
if context.is_mutating_use() || is_borrow_of_interior_mut {
|
// insert values that violate the layout constraints.
|
||||||
self.check_mut_borrowing_layout_constrained_field(
|
if context.is_mutating_use() || is_borrow_of_interior_mut {
|
||||||
place, context.is_mutating_use(),
|
self.check_mut_borrowing_layout_constrained_field(
|
||||||
);
|
place, context.is_mutating_use(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let old_source_info = self.source_info;
|
||||||
|
if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
|
||||||
|
if self.body.local_decls[*local].internal {
|
||||||
|
// Internal locals are used in the `move_val_init` desugaring.
|
||||||
|
// We want to check unsafety against the source info of the
|
||||||
|
// desugaring, rather than the source info of the RHS.
|
||||||
|
self.source_info = self.body.local_decls[*local].source_info;
|
||||||
}
|
}
|
||||||
let old_source_info = self.source_info;
|
}
|
||||||
if let (PlaceBase::Local(local), None) = (&place.base, &proj.base) {
|
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||||
if self.body.local_decls[*local].internal {
|
match base_ty.sty {
|
||||||
// Internal locals are used in the `move_val_init` desugaring.
|
ty::RawPtr(..) => {
|
||||||
// We want to check unsafety against the source info of the
|
self.require_unsafe("dereference of raw pointer",
|
||||||
// desugaring, rather than the source info of the RHS.
|
"raw pointers may be NULL, dangling or unaligned; they can violate \
|
||||||
self.source_info = self.body.local_decls[*local].source_info;
|
aliasing rules and cause data races: all of these are undefined \
|
||||||
}
|
behavior", UnsafetyViolationKind::General)
|
||||||
}
|
}
|
||||||
let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
|
ty::Adt(adt, _) => {
|
||||||
match base_ty.sty {
|
if adt.is_union() {
|
||||||
ty::RawPtr(..) => {
|
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
|
||||||
self.require_unsafe("dereference of raw pointer",
|
context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
|
||||||
"raw pointers may be NULL, dangling or unaligned; they can violate \
|
context == PlaceContext::MutatingUse(
|
||||||
aliasing rules and cause data races: all of these are undefined \
|
MutatingUseContext::AsmOutput
|
||||||
behavior", UnsafetyViolationKind::General)
|
)
|
||||||
}
|
{
|
||||||
ty::Adt(adt, _) => {
|
let elem_ty = match elem {
|
||||||
if adt.is_union() {
|
ProjectionElem::Field(_, ty) => ty,
|
||||||
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
|
_ => span_bug!(
|
||||||
context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
|
|
||||||
context == PlaceContext::MutatingUse(
|
|
||||||
MutatingUseContext::AsmOutput
|
|
||||||
)
|
|
||||||
{
|
|
||||||
let elem_ty = match proj.elem {
|
|
||||||
ProjectionElem::Field(_, ty) => ty,
|
|
||||||
_ => span_bug!(
|
|
||||||
self.source_info.span,
|
|
||||||
"non-field projection {:?} from union?",
|
|
||||||
place)
|
|
||||||
};
|
|
||||||
if !elem_ty.is_copy_modulo_regions(
|
|
||||||
self.tcx,
|
|
||||||
self.param_env,
|
|
||||||
self.source_info.span,
|
self.source_info.span,
|
||||||
) {
|
"non-field projection {:?} from union?",
|
||||||
self.require_unsafe(
|
place)
|
||||||
"assignment to non-`Copy` union field",
|
};
|
||||||
"the previous content of the field will be dropped, which \
|
if !elem_ty.is_copy_modulo_regions(
|
||||||
causes undefined behavior if the field was not properly \
|
self.tcx,
|
||||||
initialized", UnsafetyViolationKind::General)
|
self.param_env,
|
||||||
} else {
|
self.source_info.span,
|
||||||
// write to non-move union, safe
|
) {
|
||||||
}
|
self.require_unsafe(
|
||||||
|
"assignment to non-`Copy` union field",
|
||||||
|
"the previous content of the field will be dropped, which \
|
||||||
|
causes undefined behavior if the field was not properly \
|
||||||
|
initialized", UnsafetyViolationKind::General)
|
||||||
} else {
|
} else {
|
||||||
self.require_unsafe("access to union field",
|
// write to non-move union, safe
|
||||||
"the field may not be properly initialized: using \
|
|
||||||
uninitialized data will cause undefined behavior",
|
|
||||||
UnsafetyViolationKind::General)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.require_unsafe("access to union field",
|
||||||
|
"the field may not be properly initialized: using \
|
||||||
|
uninitialized data will cause undefined behavior",
|
||||||
|
UnsafetyViolationKind::General)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
self.source_info = old_source_info;
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
self.source_info = old_source_info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -407,12 +407,13 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
is_mut_use: bool,
|
is_mut_use: bool,
|
||||||
) {
|
) {
|
||||||
let mut projection = &place.projection;
|
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||||
while let Some(proj) = projection {
|
let proj_base = &place.projection[..i];
|
||||||
match proj.elem {
|
|
||||||
|
match elem {
|
||||||
ProjectionElem::Field(..) => {
|
ProjectionElem::Field(..) => {
|
||||||
let ty =
|
let ty =
|
||||||
Place::ty_from(&place.base, &proj.base, &self.body.local_decls, self.tcx)
|
Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx)
|
||||||
.ty;
|
.ty;
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
|
ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
|
||||||
|
|
@ -447,7 +448,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
projection = &proj.base;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements {
|
||||||
location: Location) {
|
location: Location) {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::AscribeUserType(..)
|
StatementKind::AscribeUserType(..)
|
||||||
| StatementKind::Assign(_, box Rvalue::Ref(_, BorrowKind::Shallow, _))
|
| StatementKind::Assign(box(_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
|
||||||
| StatementKind::FakeRead(..) => statement.make_nop(),
|
| StatementKind::FakeRead(..) => statement.make_nop(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,53 +282,53 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
|
|
||||||
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
||||||
trace!("eval_place(place={:?})", place);
|
trace!("eval_place(place={:?})", place);
|
||||||
place.iterate(|place_base, place_projection| {
|
let mut eval = match place.base {
|
||||||
let mut eval = match place_base {
|
PlaceBase::Local(loc) => self.get_const(loc).clone()?,
|
||||||
PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
|
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
|
||||||
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
|
let generics = self.tcx.generics_of(self.source.def_id());
|
||||||
let generics = self.tcx.generics_of(self.source.def_id());
|
if generics.requires_monomorphization(self.tcx) {
|
||||||
if generics.requires_monomorphization(self.tcx) {
|
// FIXME: can't handle code with generics
|
||||||
// FIXME: can't handle code with generics
|
return None;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
|
|
||||||
let instance = Instance::new(self.source.def_id(), substs);
|
|
||||||
let cid = GlobalId {
|
|
||||||
instance,
|
|
||||||
promoted: Some(*promoted),
|
|
||||||
};
|
|
||||||
let res = self.use_ecx(source_info, |this| {
|
|
||||||
this.ecx.const_eval_raw(cid)
|
|
||||||
})?;
|
|
||||||
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
|
||||||
res.into()
|
|
||||||
}
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
for proj in place_projection {
|
|
||||||
match proj.elem {
|
|
||||||
ProjectionElem::Field(field, _) => {
|
|
||||||
trace!("field proj on {:?}", proj.base);
|
|
||||||
eval = self.use_ecx(source_info, |this| {
|
|
||||||
this.ecx.operand_field(eval, field.index() as u64)
|
|
||||||
})?;
|
|
||||||
},
|
|
||||||
ProjectionElem::Deref => {
|
|
||||||
trace!("processing deref");
|
|
||||||
eval = self.use_ecx(source_info, |this| {
|
|
||||||
this.ecx.deref_operand(eval)
|
|
||||||
})?.into();
|
|
||||||
}
|
|
||||||
// We could get more projections by using e.g., `operand_projection`,
|
|
||||||
// but we do not even have the stack frame set up properly so
|
|
||||||
// an `Index` projection would throw us off-track.
|
|
||||||
_ => return None,
|
|
||||||
}
|
}
|
||||||
|
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
|
||||||
|
let instance = Instance::new(self.source.def_id(), substs);
|
||||||
|
let cid = GlobalId {
|
||||||
|
instance,
|
||||||
|
promoted: Some(promoted),
|
||||||
|
};
|
||||||
|
let res = self.use_ecx(source_info, |this| {
|
||||||
|
this.ecx.const_eval_raw(cid)
|
||||||
|
})?;
|
||||||
|
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
||||||
|
res.into()
|
||||||
}
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
Some(eval)
|
for (i, elem) in place.projection.iter().enumerate() {
|
||||||
})
|
let proj_base = &place.projection[..i];
|
||||||
|
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Field(field, _) => {
|
||||||
|
trace!("field proj on {:?}", proj_base);
|
||||||
|
eval = self.use_ecx(source_info, |this| {
|
||||||
|
this.ecx.operand_field(eval, field.index() as u64)
|
||||||
|
})?;
|
||||||
|
},
|
||||||
|
ProjectionElem::Deref => {
|
||||||
|
trace!("processing deref");
|
||||||
|
eval = self.use_ecx(source_info, |this| {
|
||||||
|
this.ecx.deref_operand(eval)
|
||||||
|
})?.into();
|
||||||
|
}
|
||||||
|
// We could get more projections by using e.g., `operand_projection`,
|
||||||
|
// but we do not even have the stack frame set up properly so
|
||||||
|
// an `Index` projection would throw us off-track.
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(eval)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
||||||
|
|
@ -665,7 +665,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
trace!("visit_statement: {:?}", statement);
|
trace!("visit_statement: {:?}", statement);
|
||||||
if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
|
if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind {
|
||||||
let place_ty: Ty<'tcx> = place
|
let place_ty: Ty<'tcx> = place
|
||||||
.ty(&self.local_decls, self.tcx)
|
.ty(&self.local_decls, self.tcx)
|
||||||
.ty;
|
.ty;
|
||||||
|
|
@ -673,7 +673,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
||||||
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
|
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *place {
|
} = *place {
|
||||||
trace!("checking whether {:?} can be stored to {:?}", value, local);
|
trace!("checking whether {:?} can be stored to {:?}", value, local);
|
||||||
if self.can_const_prop[local] {
|
if self.can_const_prop[local] {
|
||||||
|
|
|
||||||
|
|
@ -94,11 +94,13 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
||||||
// That use of the source must be an assignment.
|
// That use of the source must be an assignment.
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place {
|
box(
|
||||||
base: PlaceBase::Local(local),
|
Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(local),
|
||||||
},
|
projection: box [],
|
||||||
box Rvalue::Use(ref operand)
|
},
|
||||||
|
Rvalue::Use(ref operand)
|
||||||
|
)
|
||||||
) if local == dest_local => {
|
) if local == dest_local => {
|
||||||
let maybe_action = match *operand {
|
let maybe_action = match *operand {
|
||||||
Operand::Copy(ref src_place) |
|
Operand::Copy(ref src_place) |
|
||||||
|
|
@ -148,24 +150,28 @@ fn eliminate_self_assignments(
|
||||||
if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
|
if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place {
|
box(
|
||||||
base: PlaceBase::Local(local),
|
Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(local),
|
||||||
},
|
projection: box [],
|
||||||
box Rvalue::Use(Operand::Copy(Place {
|
},
|
||||||
base: PlaceBase::Local(src_local),
|
Rvalue::Use(Operand::Copy(Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(src_local),
|
||||||
})),
|
projection: box [],
|
||||||
|
})),
|
||||||
|
)
|
||||||
) |
|
) |
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
Place {
|
box(
|
||||||
base: PlaceBase::Local(local),
|
Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(local),
|
||||||
},
|
projection: box [],
|
||||||
box Rvalue::Use(Operand::Move(Place {
|
},
|
||||||
base: PlaceBase::Local(src_local),
|
Rvalue::Use(Operand::Move(Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(src_local),
|
||||||
})),
|
projection: box [],
|
||||||
|
})),
|
||||||
|
)
|
||||||
) if local == dest_local && dest_local == src_local => {}
|
) if local == dest_local && dest_local == src_local => {}
|
||||||
_ => {
|
_ => {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -194,7 +200,7 @@ impl<'tcx> Action<'tcx> {
|
||||||
// The source must be a local.
|
// The source must be a local.
|
||||||
let src_local = if let Place {
|
let src_local = if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *src_place {
|
} = *src_place {
|
||||||
local
|
local
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -351,11 +357,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
||||||
match *operand {
|
match *operand {
|
||||||
Operand::Copy(Place {
|
Operand::Copy(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) |
|
}) |
|
||||||
Operand::Move(Place {
|
Operand::Move(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) if local == self.dest_local => {}
|
}) if local == self.dest_local => {}
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
||||||
for bb in basic_blocks {
|
for bb in basic_blocks {
|
||||||
bb.expand_statements(|stmt| {
|
bb.expand_statements(|stmt| {
|
||||||
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
|
// FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
|
||||||
if let StatementKind::Assign(_, ref rhs) = stmt.kind {
|
if let StatementKind::Assign(box(_, ref rhs)) = stmt.kind {
|
||||||
if let Rvalue::Aggregate(ref kind, _) = **rhs {
|
if let Rvalue::Aggregate(ref kind, _) = *rhs {
|
||||||
// FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
|
// FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
|
||||||
if let AggregateKind::Array(_) = **kind {
|
if let AggregateKind::Array(_) = **kind {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -28,7 +28,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
|
||||||
let stmt = stmt.replace_nop();
|
let stmt = stmt.replace_nop();
|
||||||
let source_info = stmt.source_info;
|
let source_info = stmt.source_info;
|
||||||
let (lhs, kind, operands) = match stmt.kind {
|
let (lhs, kind, operands) = match stmt.kind {
|
||||||
StatementKind::Assign(lhs, box rvalue) => {
|
StatementKind::Assign(box(lhs, rvalue)) => {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
|
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
|
||||||
_ => bug!()
|
_ => bug!()
|
||||||
|
|
|
||||||
|
|
@ -236,47 +236,34 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
|
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
|
||||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||||
match p {
|
ProjectionElem::Field(idx, _) => *idx == field,
|
||||||
&Projection {
|
_ => false,
|
||||||
elem: ProjectionElem::Field(idx, _), ..
|
|
||||||
} => idx == field,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
|
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
|
||||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||||
match p {
|
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
|
||||||
&Projection {
|
*offset == index
|
||||||
elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
|
|
||||||
} => offset == index,
|
|
||||||
&Projection {
|
|
||||||
elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
|
|
||||||
} => size - offset == index,
|
|
||||||
_ => false
|
|
||||||
}
|
}
|
||||||
|
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
|
||||||
|
size - offset == index
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
|
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
|
||||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
|
||||||
match p {
|
*e == ProjectionElem::Deref
|
||||||
&Projection { elem: ProjectionElem::Deref, .. } => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
|
fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
|
||||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
|
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||||
match p {
|
ProjectionElem::Downcast(_, idx) => *idx == variant,
|
||||||
&Projection {
|
_ => false
|
||||||
elem: ProjectionElem::Downcast(_, idx), ..
|
|
||||||
} => idx == variant,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,7 +452,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
|
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
|
||||||
|
|
||||||
let assign = Statement {
|
let assign = Statement {
|
||||||
kind: StatementKind::Assign(location.clone(), box Rvalue::Use(value.clone())),
|
kind: StatementKind::Assign(box(location.clone(), Rvalue::Use(value.clone()))),
|
||||||
source_info: terminator.source_info
|
source_info: terminator.source_info
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
||||||
if place.base == PlaceBase::Local(self_arg()) {
|
if place.base == PlaceBase::Local(self_arg()) {
|
||||||
replace_base(place, Place {
|
replace_base(place, Place {
|
||||||
base: PlaceBase::Local(self_arg()),
|
base: PlaceBase::Local(self_arg()),
|
||||||
projection: Some(Box::new(Projection {
|
projection: Box::new([ProjectionElem::Deref]),
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
})),
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.super_place(place, context, location);
|
self.super_place(place, context, location);
|
||||||
|
|
@ -137,10 +134,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
||||||
if place.base == PlaceBase::Local(self_arg()) {
|
if place.base == PlaceBase::Local(self_arg()) {
|
||||||
replace_base(place, Place {
|
replace_base(place, Place {
|
||||||
base: PlaceBase::Local(self_arg()),
|
base: PlaceBase::Local(self_arg()),
|
||||||
projection: Some(Box::new(Projection {
|
projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
|
|
||||||
})),
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.super_place(place, context, location);
|
self.super_place(place, context, location);
|
||||||
|
|
@ -149,13 +143,12 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
|
fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
|
||||||
let mut projection = &mut place.projection;
|
|
||||||
while let Some(box proj) = projection {
|
|
||||||
projection = &mut proj.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
place.base = new_base.base;
|
place.base = new_base.base;
|
||||||
*projection = new_base.projection;
|
|
||||||
|
let mut new_projection = new_base.projection.to_vec();
|
||||||
|
new_projection.append(&mut place.projection.to_vec());
|
||||||
|
|
||||||
|
place.projection = new_projection.into_boxed_slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_arg() -> Local {
|
fn self_arg() -> Local {
|
||||||
|
|
@ -210,13 +203,12 @@ impl TransformVisitor<'tcx> {
|
||||||
fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
|
fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
|
||||||
let self_place = Place::from(self_arg());
|
let self_place = Place::from(self_arg());
|
||||||
let base = self_place.downcast_unnamed(variant_index);
|
let base = self_place.downcast_unnamed(variant_index);
|
||||||
let field = Projection {
|
let mut projection = base.projection.to_vec();
|
||||||
base: base.projection,
|
projection.push(ProjectionElem::Field(Field::new(idx), ty));
|
||||||
elem: ProjectionElem::Field(Field::new(idx), ty),
|
|
||||||
};
|
|
||||||
Place {
|
Place {
|
||||||
base: base.base,
|
base: base.base,
|
||||||
projection: Some(Box::new(field)),
|
projection: projection.into_boxed_slice(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,7 +217,10 @@ impl TransformVisitor<'tcx> {
|
||||||
let self_place = Place::from(self_arg());
|
let self_place = Place::from(self_arg());
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::SetDiscriminant { place: self_place, variant_index: state_disc },
|
kind: StatementKind::SetDiscriminant {
|
||||||
|
place: box self_place,
|
||||||
|
variant_index: state_disc,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +233,7 @@ impl TransformVisitor<'tcx> {
|
||||||
let self_place = Place::from(self_arg());
|
let self_place = Place::from(self_arg());
|
||||||
let assign = Statement {
|
let assign = Statement {
|
||||||
source_info: source_info(body),
|
source_info: source_info(body),
|
||||||
kind: StatementKind::Assign(temp.clone(), box Rvalue::Discriminant(self_place)),
|
kind: StatementKind::Assign(box(temp.clone(), Rvalue::Discriminant(self_place))),
|
||||||
};
|
};
|
||||||
(assign, temp)
|
(assign, temp)
|
||||||
}
|
}
|
||||||
|
|
@ -296,8 +291,12 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
||||||
// We must assign the value first in case it gets declared dead below
|
// We must assign the value first in case it gets declared dead below
|
||||||
data.statements.push(Statement {
|
data.statements.push(Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Assign(Place::RETURN_PLACE,
|
kind: StatementKind::Assign(
|
||||||
box self.make_state(state_idx, v)),
|
box(
|
||||||
|
Place::return_place(),
|
||||||
|
self.make_state(state_idx, v)
|
||||||
|
)
|
||||||
|
),
|
||||||
});
|
});
|
||||||
let state = if let Some(resume) = resume { // Yield
|
let state = if let Some(resume) = resume { // Yield
|
||||||
let state = 3 + self.suspension_points.len();
|
let state = 3 + self.suspension_points.len();
|
||||||
|
|
@ -848,7 +847,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
|
||||||
kind: TerminatorKind::Drop {
|
kind: TerminatorKind::Drop {
|
||||||
location: Place {
|
location: Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
},
|
},
|
||||||
target,
|
target,
|
||||||
unwind
|
unwind
|
||||||
|
|
@ -937,7 +936,7 @@ fn create_generator_drop_shim<'tcx>(
|
||||||
// Alias tracking must know we changed the type
|
// Alias tracking must know we changed the type
|
||||||
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
|
body.basic_blocks_mut()[START_BLOCK].statements.insert(0, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Retag(RetagKind::Raw, Place::from(self_arg())),
|
kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,22 +425,20 @@ impl Inliner<'tcx> {
|
||||||
// writes to `i`. To prevent this we need to create a temporary
|
// writes to `i`. To prevent this we need to create a temporary
|
||||||
// borrow of the place and pass the destination as `*temp` instead.
|
// borrow of the place and pass the destination as `*temp` instead.
|
||||||
fn dest_needs_borrow(place: &Place<'_>) -> bool {
|
fn dest_needs_borrow(place: &Place<'_>) -> bool {
|
||||||
place.iterate(|place_base, place_projection| {
|
for elem in place.projection.iter() {
|
||||||
for proj in place_projection {
|
match elem {
|
||||||
match proj.elem {
|
ProjectionElem::Deref |
|
||||||
ProjectionElem::Deref |
|
ProjectionElem::Index(_) => return true,
|
||||||
ProjectionElem::Index(_) => return true,
|
_ => {}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match place_base {
|
match place.base {
|
||||||
// Static variables need a borrow because the callee
|
// Static variables need a borrow because the callee
|
||||||
// might modify the same static.
|
// might modify the same static.
|
||||||
PlaceBase::Static(_) => true,
|
PlaceBase::Static(_) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let dest = if dest_needs_borrow(&destination.0) {
|
let dest = if dest_needs_borrow(&destination.0) {
|
||||||
|
|
@ -459,7 +457,7 @@ impl Inliner<'tcx> {
|
||||||
|
|
||||||
let stmt = Statement {
|
let stmt = Statement {
|
||||||
source_info: callsite.location,
|
source_info: callsite.location,
|
||||||
kind: StatementKind::Assign(tmp.clone(), box dest)
|
kind: StatementKind::Assign(box(tmp.clone(), dest))
|
||||||
};
|
};
|
||||||
caller_body[callsite.bb]
|
caller_body[callsite.bb]
|
||||||
.statements.push(stmt);
|
.statements.push(stmt);
|
||||||
|
|
@ -591,7 +589,7 @@ impl Inliner<'tcx> {
|
||||||
|
|
||||||
if let Operand::Move(Place {
|
if let Operand::Move(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) = arg {
|
}) = arg {
|
||||||
if caller_body.local_kind(local) == LocalKind::Temp {
|
if caller_body.local_kind(local) == LocalKind::Temp {
|
||||||
// Reuse the operand if it's a temporary already
|
// Reuse the operand if it's a temporary already
|
||||||
|
|
@ -610,7 +608,7 @@ impl Inliner<'tcx> {
|
||||||
|
|
||||||
let stmt = Statement {
|
let stmt = Statement {
|
||||||
source_info: callsite.location,
|
source_info: callsite.location,
|
||||||
kind: StatementKind::Assign(Place::from(arg_tmp), box arg),
|
kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)),
|
||||||
};
|
};
|
||||||
caller_body[callsite.bb].statements.push(stmt);
|
caller_body[callsite.bb].statements.push(stmt);
|
||||||
arg_tmp
|
arg_tmp
|
||||||
|
|
@ -660,7 +658,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||||
match self.destination {
|
match self.destination {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(l),
|
base: PlaceBase::Local(l),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} => {
|
} => {
|
||||||
*local = l;
|
*local = l;
|
||||||
return;
|
return;
|
||||||
|
|
@ -684,7 +682,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||||
match place {
|
match place {
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(RETURN_PLACE),
|
base: PlaceBase::Local(RETURN_PLACE),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} => {
|
} => {
|
||||||
// Return pointer; update the place itself
|
// Return pointer; update the place itself
|
||||||
*place = self.destination.clone();
|
*place = self.destination.clone();
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,21 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
||||||
let new_place = match *rvalue {
|
let new_place = match *rvalue {
|
||||||
Rvalue::Ref(_, _, Place {
|
Rvalue::Ref(_, _, Place {
|
||||||
ref mut base,
|
ref mut base,
|
||||||
projection: Some(ref mut projection),
|
projection: ref mut projection @ box [.., _],
|
||||||
}) => Place {
|
}) => {
|
||||||
// Replace with dummy
|
if let box [proj_l @ .., proj_r] = projection {
|
||||||
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
|
let place = Place {
|
||||||
projection: projection.base.take(),
|
// Replace with dummy
|
||||||
},
|
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
|
||||||
|
projection: proj_l.to_vec().into_boxed_slice(),
|
||||||
|
};
|
||||||
|
*projection = vec![proj_r.clone()].into_boxed_slice();
|
||||||
|
|
||||||
|
place
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => bug!("Detected `&*` but didn't find `&*`!"),
|
_ => bug!("Detected `&*` but didn't find `&*`!"),
|
||||||
};
|
};
|
||||||
*rvalue = Rvalue::Use(Operand::Copy(new_place))
|
*rvalue = Rvalue::Use(Operand::Copy(new_place))
|
||||||
|
|
@ -83,13 +92,11 @@ impl OptimizationFinder<'b, 'tcx> {
|
||||||
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
|
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
|
||||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||||
if let Rvalue::Ref(_, _, Place {
|
if let Rvalue::Ref(_, _, Place {
|
||||||
ref base,
|
base,
|
||||||
projection: Some(ref projection),
|
projection: box [proj_base @ .., ProjectionElem::Deref],
|
||||||
}) = *rvalue {
|
}) = rvalue {
|
||||||
if let ProjectionElem::Deref = projection.elem {
|
if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
|
||||||
if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() {
|
self.optimizations.and_stars.insert(location);
|
||||||
self.optimizations.and_stars.insert(location);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
scope: OUTERMOST_SOURCE_SCOPE
|
scope: OUTERMOST_SOURCE_SCOPE
|
||||||
},
|
},
|
||||||
kind: StatementKind::Assign(Place::from(dest), box rvalue)
|
kind: StatementKind::Assign(box(Place::from(dest), rvalue))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,10 +222,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
// First, take the Rvalue or Call out of the source MIR,
|
// First, take the Rvalue or Call out of the source MIR,
|
||||||
// or duplicate it, depending on keep_original.
|
// or duplicate it, depending on keep_original.
|
||||||
if loc.statement_index < no_stmts {
|
if loc.statement_index < no_stmts {
|
||||||
let (rvalue, source_info) = {
|
let (mut rvalue, source_info) = {
|
||||||
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
||||||
let rhs = match statement.kind {
|
let rhs = match statement.kind {
|
||||||
StatementKind::Assign(_, ref mut rhs) => rhs,
|
StatementKind::Assign(box(_, ref mut rhs)) => rhs,
|
||||||
_ => {
|
_ => {
|
||||||
span_bug!(statement.source_info.span, "{:?} is not an assignment",
|
span_bug!(statement.source_info.span, "{:?} is not an assignment",
|
||||||
statement);
|
statement);
|
||||||
|
|
@ -235,12 +235,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
(if self.keep_original {
|
(if self.keep_original {
|
||||||
rhs.clone()
|
rhs.clone()
|
||||||
} else {
|
} else {
|
||||||
let unit = box Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
|
let unit = Rvalue::Aggregate(box AggregateKind::Tuple, vec![]);
|
||||||
mem::replace(rhs, unit)
|
mem::replace(rhs, unit)
|
||||||
}, statement.source_info)
|
}, statement.source_info)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rvalue = *rvalue;
|
|
||||||
self.visit_rvalue(&mut rvalue, loc);
|
self.visit_rvalue(&mut rvalue, loc);
|
||||||
self.assign(new_temp, rvalue, source_info.span);
|
self.assign(new_temp, rvalue, source_info.span);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -318,7 +317,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
ty,
|
ty,
|
||||||
def_id,
|
def_id,
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
||||||
|
|
@ -326,7 +325,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
Candidate::Ref(loc) => {
|
Candidate::Ref(loc) => {
|
||||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
|
StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||||
// Use the underlying local for this (necessarily interior) borrow.
|
// Use the underlying local for this (necessarily interior) borrow.
|
||||||
let ty = place.base.ty(local_decls).ty;
|
let ty = place.base.ty(local_decls).ty;
|
||||||
let span = statement.source_info.span;
|
let span = statement.source_info.span;
|
||||||
|
|
@ -334,9 +333,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
Operand::Move(Place {
|
Operand::Move(Place {
|
||||||
base: mem::replace(
|
base: mem::replace(
|
||||||
&mut place.base,
|
&mut place.base,
|
||||||
promoted_place(ty, span).base
|
promoted_place(ty, span).base,
|
||||||
),
|
),
|
||||||
projection: None,
|
projection: box [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => bug!()
|
_ => bug!()
|
||||||
|
|
@ -345,7 +344,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
Candidate::Repeat(loc) => {
|
Candidate::Repeat(loc) => {
|
||||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
|
StatementKind::Assign(box(_, Rvalue::Repeat(ref mut operand, _))) => {
|
||||||
let ty = operand.ty(local_decls, self.tcx);
|
let ty = operand.ty(local_decls, self.tcx);
|
||||||
let span = statement.source_info.span;
|
let span = statement.source_info.span;
|
||||||
mem::replace(
|
mem::replace(
|
||||||
|
|
@ -420,10 +419,10 @@ pub fn promote_candidates<'tcx>(
|
||||||
Candidate::Repeat(Location { block, statement_index }) |
|
Candidate::Repeat(Location { block, statement_index }) |
|
||||||
Candidate::Ref(Location { block, statement_index }) => {
|
Candidate::Ref(Location { block, statement_index }) => {
|
||||||
match body[block].statements[statement_index].kind {
|
match body[block].statements[statement_index].kind {
|
||||||
StatementKind::Assign(Place {
|
StatementKind::Assign(box(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, _) => {
|
}, _)) => {
|
||||||
if temps[local] == TempState::PromotedOut {
|
if temps[local] == TempState::PromotedOut {
|
||||||
// Already promoted.
|
// Already promoted.
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -473,10 +472,10 @@ pub fn promote_candidates<'tcx>(
|
||||||
for block in body.basic_blocks_mut() {
|
for block in body.basic_blocks_mut() {
|
||||||
block.statements.retain(|statement| {
|
block.statements.retain(|statement| {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(Place {
|
StatementKind::Assign(box(Place {
|
||||||
base: PlaceBase::Local(index),
|
base: PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, _) |
|
}, _)) |
|
||||||
StatementKind::StorageLive(index) |
|
StatementKind::StorageLive(index) |
|
||||||
StatementKind::StorageDead(index) => {
|
StatementKind::StorageDead(index) => {
|
||||||
!promoted(index)
|
!promoted(index)
|
||||||
|
|
@ -488,7 +487,7 @@ pub fn promote_candidates<'tcx>(
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::Drop { location: Place {
|
TerminatorKind::Drop { location: Place {
|
||||||
base: PlaceBase::Local(index),
|
base: PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, target, .. } => {
|
}, target, .. } => {
|
||||||
if promoted(index) {
|
if promoted(index) {
|
||||||
terminator.kind = TerminatorKind::Goto {
|
terminator.kind = TerminatorKind::Goto {
|
||||||
|
|
|
||||||
|
|
@ -187,26 +187,28 @@ trait Qualif {
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
place: PlaceRef<'_, 'tcx>,
|
place: PlaceRef<'_, 'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let proj = place.projection.as_ref().unwrap();
|
if let [proj_base @ .., elem] = place.projection {
|
||||||
|
let base_qualif = Self::in_place(cx, PlaceRef {
|
||||||
|
base: place.base,
|
||||||
|
projection: proj_base,
|
||||||
|
});
|
||||||
|
let qualif = base_qualif && Self::mask_for_ty(
|
||||||
|
cx,
|
||||||
|
Place::ty_from(place.base, proj_base, cx.body, cx.tcx)
|
||||||
|
.projection_ty(cx.tcx, elem)
|
||||||
|
.ty,
|
||||||
|
);
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Deref |
|
||||||
|
ProjectionElem::Subslice { .. } |
|
||||||
|
ProjectionElem::Field(..) |
|
||||||
|
ProjectionElem::ConstantIndex { .. } |
|
||||||
|
ProjectionElem::Downcast(..) => qualif,
|
||||||
|
|
||||||
let base_qualif = Self::in_place(cx, PlaceRef {
|
ProjectionElem::Index(local) => qualif || Self::in_local(cx, *local),
|
||||||
base: place.base,
|
}
|
||||||
projection: &proj.base,
|
} else {
|
||||||
});
|
bug!("This should be called if projection is not empty");
|
||||||
let qualif = base_qualif && Self::mask_for_ty(
|
|
||||||
cx,
|
|
||||||
Place::ty_from(place.base, &proj.base, cx.body, cx.tcx)
|
|
||||||
.projection_ty(cx.tcx, &proj.elem)
|
|
||||||
.ty,
|
|
||||||
);
|
|
||||||
match proj.elem {
|
|
||||||
ProjectionElem::Deref |
|
|
||||||
ProjectionElem::Subslice { .. } |
|
|
||||||
ProjectionElem::Field(..) |
|
|
||||||
ProjectionElem::ConstantIndex { .. } |
|
|
||||||
ProjectionElem::Downcast(..) => qualif,
|
|
||||||
|
|
||||||
ProjectionElem::Index(local) => qualif || Self::in_local(cx, local),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,24 +223,24 @@ trait Qualif {
|
||||||
match place {
|
match place {
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => Self::in_local(cx, *local),
|
} => Self::in_local(cx, *local),
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Static(box Static {
|
base: PlaceBase::Static(box Static {
|
||||||
kind: StaticKind::Promoted(..),
|
kind: StaticKind::Promoted(..),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => bug!("qualifying already promoted MIR"),
|
} => bug!("qualifying already promoted MIR"),
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: PlaceBase::Static(static_),
|
base: PlaceBase::Static(static_),
|
||||||
projection: None,
|
projection: [],
|
||||||
} => {
|
} => {
|
||||||
Self::in_static(cx, static_)
|
Self::in_static(cx, static_)
|
||||||
},
|
},
|
||||||
PlaceRef {
|
PlaceRef {
|
||||||
base: _,
|
base: _,
|
||||||
projection: Some(_),
|
projection: [.., _],
|
||||||
} => Self::in_projection(cx, place),
|
} => Self::in_projection(cx, place),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,13 +291,13 @@ trait Qualif {
|
||||||
|
|
||||||
Rvalue::Ref(_, _, ref place) => {
|
Rvalue::Ref(_, _, ref place) => {
|
||||||
// Special-case reborrows to be more like a copy of the reference.
|
// Special-case reborrows to be more like a copy of the reference.
|
||||||
if let Some(ref proj) = place.projection {
|
if let box [proj_base @ .., elem] = &place.projection {
|
||||||
if let ProjectionElem::Deref = proj.elem {
|
if ProjectionElem::Deref == *elem {
|
||||||
let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty;
|
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
|
||||||
if let ty::Ref(..) = base_ty.sty {
|
if let ty::Ref(..) = base_ty.sty {
|
||||||
return Self::in_place(cx, PlaceRef {
|
return Self::in_place(cx, PlaceRef {
|
||||||
base: &place.base,
|
base: &place.base,
|
||||||
projection: &proj.base,
|
projection: proj_base,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -453,30 +455,32 @@ impl Qualif for IsNotPromotable {
|
||||||
cx: &ConstCx<'_, 'tcx>,
|
cx: &ConstCx<'_, 'tcx>,
|
||||||
place: PlaceRef<'_, 'tcx>,
|
place: PlaceRef<'_, 'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let proj = place.projection.as_ref().unwrap();
|
if let [proj_base @ .., elem] = place.projection {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Deref |
|
||||||
|
ProjectionElem::Downcast(..) => return true,
|
||||||
|
|
||||||
match proj.elem {
|
ProjectionElem::ConstantIndex {..} |
|
||||||
ProjectionElem::Deref |
|
ProjectionElem::Subslice {..} |
|
||||||
ProjectionElem::Downcast(..) => return true,
|
ProjectionElem::Index(_) => {}
|
||||||
|
|
||||||
ProjectionElem::ConstantIndex {..} |
|
ProjectionElem::Field(..) => {
|
||||||
ProjectionElem::Subslice {..} |
|
if cx.mode == Mode::NonConstFn {
|
||||||
ProjectionElem::Index(_) => {}
|
let base_ty = Place::ty_from(place.base, proj_base, cx.body, cx.tcx).ty;
|
||||||
|
if let Some(def) = base_ty.ty_adt_def() {
|
||||||
ProjectionElem::Field(..) => {
|
// No promotion of union field accesses.
|
||||||
if cx.mode == Mode::NonConstFn {
|
if def.is_union() {
|
||||||
let base_ty = Place::ty_from(place.base, &proj.base, cx.body, cx.tcx).ty;
|
return true;
|
||||||
if let Some(def) = base_ty.ty_adt_def() {
|
}
|
||||||
// No promotion of union field accesses.
|
|
||||||
if def.is_union() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Self::in_projection_structurally(cx, place)
|
Self::in_projection_structurally(cx, place)
|
||||||
|
} else {
|
||||||
|
bug!("This should be called if projection is not empty");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
|
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
|
||||||
|
|
@ -806,23 +810,18 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||||
// We might have a candidate for promotion.
|
// We might have a candidate for promotion.
|
||||||
let candidate = Candidate::Ref(location);
|
let candidate = Candidate::Ref(location);
|
||||||
// Start by traversing to the "base", with non-deref projections removed.
|
// Start by traversing to the "base", with non-deref projections removed.
|
||||||
let mut place_projection = &place.projection;
|
let deref_proj =
|
||||||
while let Some(proj) = place_projection {
|
place.projection.iter().rev().find(|&elem| *elem == ProjectionElem::Deref);
|
||||||
if proj.elem == ProjectionElem::Deref {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
place_projection = &proj.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"qualify_consts: promotion candidate: place={:?} {:?}",
|
"qualify_consts: promotion candidate: place={:?} {:?}",
|
||||||
place.base, place_projection
|
place.base, deref_proj
|
||||||
);
|
);
|
||||||
// We can only promote interior borrows of promotable temps (non-temps
|
// We can only promote interior borrows of promotable temps (non-temps
|
||||||
// don't get promoted anyway).
|
// don't get promoted anyway).
|
||||||
// (If we bailed out of the loop due to a `Deref` above, we will definitely
|
// (If we bailed out of the loop due to a `Deref` above, we will definitely
|
||||||
// not enter the conditional here.)
|
// not enter the conditional here.)
|
||||||
if let (PlaceBase::Local(local), None) = (&place.base, place_projection) {
|
if let (PlaceBase::Local(local), None) = (&place.base, deref_proj) {
|
||||||
if self.body.local_kind(*local) == LocalKind::Temp {
|
if self.body.local_kind(*local) == LocalKind::Temp {
|
||||||
debug!("qualify_consts: promotion candidate: local={:?}", local);
|
debug!("qualify_consts: promotion candidate: local={:?}", local);
|
||||||
// The borrowed place doesn't have `HasMutInterior`
|
// The borrowed place doesn't have `HasMutInterior`
|
||||||
|
|
@ -858,27 +857,27 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dest_projection = &dest.projection;
|
let mut dest_projection = &dest.projection[..];
|
||||||
let index = loop {
|
let index = loop {
|
||||||
match (&dest.base, dest_projection) {
|
match (&dest.base, dest_projection) {
|
||||||
// We treat all locals equal in constants
|
// We treat all locals equal in constants
|
||||||
(&PlaceBase::Local(index), None) => break index,
|
(&PlaceBase::Local(index), []) => break index,
|
||||||
// projections are transparent for assignments
|
// projections are transparent for assignments
|
||||||
// we qualify the entire destination at once, even if just a field would have
|
// we qualify the entire destination at once, even if just a field would have
|
||||||
// stricter qualification
|
// stricter qualification
|
||||||
(base, Some(proj)) => {
|
(base, [proj_base @ .., _]) => {
|
||||||
// Catch more errors in the destination. `visit_place` also checks various
|
// Catch more errors in the destination. `visit_place` also checks various
|
||||||
// projection rules like union field access and raw pointer deref
|
// projection rules like union field access and raw pointer deref
|
||||||
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
|
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
|
||||||
self.visit_place_base(base, context, location);
|
self.visit_place_base(base, context, location);
|
||||||
self.visit_projection(base, proj, context, location);
|
self.visit_projection(base, dest_projection, context, location);
|
||||||
dest_projection = &proj.base;
|
dest_projection = proj_base;
|
||||||
},
|
},
|
||||||
(&PlaceBase::Static(box Static {
|
(&PlaceBase::Static(box Static {
|
||||||
kind: StaticKind::Promoted(..),
|
kind: StaticKind::Promoted(..),
|
||||||
..
|
..
|
||||||
}), None) => bug!("promoteds don't exist yet during promotion"),
|
}), []) => bug!("promoteds don't exist yet during promotion"),
|
||||||
(&PlaceBase::Static(box Static{ kind: _, .. }), None) => {
|
(&PlaceBase::Static(box Static{ kind: _, .. }), []) => {
|
||||||
// Catch more errors in the destination. `visit_place` also checks that we
|
// Catch more errors in the destination. `visit_place` also checks that we
|
||||||
// do not try to access statics from constants or try to mutate statics
|
// do not try to access statics from constants or try to mutate statics
|
||||||
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
|
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
|
||||||
|
|
@ -983,23 +982,25 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||||
for candidate in &self.promotion_candidates {
|
for candidate in &self.promotion_candidates {
|
||||||
match *candidate {
|
match *candidate {
|
||||||
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
|
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
|
||||||
if let StatementKind::Assign(_, box Rvalue::Repeat(
|
if let StatementKind::Assign(box(_, Rvalue::Repeat(
|
||||||
Operand::Move(Place {
|
Operand::Move(Place {
|
||||||
base: PlaceBase::Local(index),
|
base: PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}),
|
}),
|
||||||
_
|
_
|
||||||
)) = self.body[bb].statements[stmt_idx].kind {
|
))) = self.body[bb].statements[stmt_idx].kind {
|
||||||
promoted_temps.insert(index);
|
promoted_temps.insert(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
||||||
if let StatementKind::Assign(
|
if let StatementKind::Assign(
|
||||||
_,
|
box(
|
||||||
box Rvalue::Ref(_, _, Place {
|
_,
|
||||||
base: PlaceBase::Local(index),
|
Rvalue::Ref(_, _, Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(index),
|
||||||
})
|
projection: box [],
|
||||||
|
})
|
||||||
|
)
|
||||||
) = self.body[bb].statements[stmt_idx].kind {
|
) = self.body[bb].statements[stmt_idx].kind {
|
||||||
promoted_temps.insert(index);
|
promoted_temps.insert(index);
|
||||||
}
|
}
|
||||||
|
|
@ -1084,7 +1085,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
fn visit_projection(
|
fn visit_projection(
|
||||||
&mut self,
|
&mut self,
|
||||||
place_base: &PlaceBase<'tcx>,
|
place_base: &PlaceBase<'tcx>,
|
||||||
proj: &Projection<'tcx>,
|
proj: &[PlaceElem<'tcx>],
|
||||||
context: PlaceContext,
|
context: PlaceContext,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
|
|
@ -1093,62 +1094,65 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
proj, context, location,
|
proj, context, location,
|
||||||
);
|
);
|
||||||
self.super_projection(place_base, proj, context, location);
|
self.super_projection(place_base, proj, context, location);
|
||||||
match proj.elem {
|
|
||||||
ProjectionElem::Deref => {
|
if let [proj_base @ .., elem] = proj {
|
||||||
if context.is_mutating_use() {
|
match elem {
|
||||||
// `not_const` errors out in const contexts
|
ProjectionElem::Deref => {
|
||||||
self.not_const()
|
if context.is_mutating_use() {
|
||||||
}
|
// `not_const` errors out in const contexts
|
||||||
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
|
self.not_const()
|
||||||
match self.mode {
|
}
|
||||||
Mode::NonConstFn => {},
|
let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
|
||||||
_ => {
|
match self.mode {
|
||||||
if let ty::RawPtr(_) = base_ty.sty {
|
Mode::NonConstFn => {},
|
||||||
if !self.tcx.features().const_raw_ptr_deref {
|
_ => {
|
||||||
emit_feature_err(
|
if let ty::RawPtr(_) = base_ty.sty {
|
||||||
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
|
if !self.tcx.features().const_raw_ptr_deref {
|
||||||
self.span, GateIssue::Language,
|
emit_feature_err(
|
||||||
&format!(
|
&self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
|
||||||
"dereferencing raw pointers in {}s is unstable",
|
self.span, GateIssue::Language,
|
||||||
self.mode,
|
&format!(
|
||||||
),
|
"dereferencing raw pointers in {}s is unstable",
|
||||||
);
|
self.mode,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ProjectionElem::ConstantIndex {..} |
|
ProjectionElem::ConstantIndex {..} |
|
||||||
ProjectionElem::Subslice {..} |
|
ProjectionElem::Subslice {..} |
|
||||||
ProjectionElem::Field(..) |
|
ProjectionElem::Field(..) |
|
||||||
ProjectionElem::Index(_) => {
|
ProjectionElem::Index(_) => {
|
||||||
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
|
let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
|
||||||
if let Some(def) = base_ty.ty_adt_def() {
|
if let Some(def) = base_ty.ty_adt_def() {
|
||||||
if def.is_union() {
|
if def.is_union() {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::ConstFn => {
|
Mode::ConstFn => {
|
||||||
if !self.tcx.features().const_fn_union {
|
if !self.tcx.features().const_fn_union {
|
||||||
emit_feature_err(
|
emit_feature_err(
|
||||||
&self.tcx.sess.parse_sess, sym::const_fn_union,
|
&self.tcx.sess.parse_sess, sym::const_fn_union,
|
||||||
self.span, GateIssue::Language,
|
self.span, GateIssue::Language,
|
||||||
"unions in const fn are unstable",
|
"unions in const fn are unstable",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
| Mode::NonConstFn
|
| Mode::NonConstFn
|
||||||
| Mode::Static
|
| Mode::Static
|
||||||
| Mode::StaticMut
|
| Mode::StaticMut
|
||||||
| Mode::Const
|
| Mode::Const
|
||||||
=> {},
|
=> {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ProjectionElem::Downcast(..) => {
|
ProjectionElem::Downcast(..) => {
|
||||||
self.not_const()
|
self.not_const()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1162,7 +1166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
// Mark the consumed locals to indicate later drops are noops.
|
// Mark the consumed locals to indicate later drops are noops.
|
||||||
if let Place {
|
if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *place {
|
} = *place {
|
||||||
self.cx.per_local[NeedsDrop].remove(local);
|
self.cx.per_local[NeedsDrop].remove(local);
|
||||||
}
|
}
|
||||||
|
|
@ -1179,11 +1183,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
||||||
// Special-case reborrows.
|
// Special-case reborrows.
|
||||||
let mut reborrow_place = None;
|
let mut reborrow_place = None;
|
||||||
if let Some(ref proj) = place.projection {
|
if let box [proj_base @ .., elem] = &place.projection {
|
||||||
if let ProjectionElem::Deref = proj.elem {
|
if *elem == ProjectionElem::Deref {
|
||||||
let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
|
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||||
if let ty::Ref(..) = base_ty.sty {
|
if let ty::Ref(..) = base_ty.sty {
|
||||||
reborrow_place = Some(&proj.base);
|
reborrow_place = Some(proj_base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1204,9 +1208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
self.visit_place_base(&place.base, ctx, location);
|
self.visit_place_base(&place.base, ctx, location);
|
||||||
if let Some(proj) = proj {
|
self.visit_projection(&place.base, proj, ctx, location);
|
||||||
self.visit_projection(&place.base, proj, ctx, location);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.super_rvalue(rvalue, location);
|
self.super_rvalue(rvalue, location);
|
||||||
}
|
}
|
||||||
|
|
@ -1477,7 +1479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
// conservatively, that drop elaboration will do.
|
// conservatively, that drop elaboration will do.
|
||||||
let needs_drop = if let Place {
|
let needs_drop = if let Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
} = *place {
|
} = *place {
|
||||||
if NeedsDrop::in_local(self, local) {
|
if NeedsDrop::in_local(self, local) {
|
||||||
Some(self.body.local_decls[local].source_info.span)
|
Some(self.body.local_decls[local].source_info.span)
|
||||||
|
|
@ -1727,7 +1729,7 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
|
||||||
TerminatorKind::Drop {
|
TerminatorKind::Drop {
|
||||||
location: Place {
|
location: Place {
|
||||||
base: PlaceBase::Local(index),
|
base: PlaceBase::Local(index),
|
||||||
projection: None,
|
projection: box [],
|
||||||
},
|
},
|
||||||
target,
|
target,
|
||||||
..
|
..
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ fn check_statement(
|
||||||
) -> McfResult {
|
) -> McfResult {
|
||||||
let span = statement.source_info.span;
|
let span = statement.source_info.span;
|
||||||
match &statement.kind {
|
match &statement.kind {
|
||||||
StatementKind::Assign(place, rval) => {
|
StatementKind::Assign(box(place, rval)) => {
|
||||||
check_place(place, span)?;
|
check_place(place, span)?;
|
||||||
check_rvalue(tcx, body, rval, span)
|
check_rvalue(tcx, body, rval, span)
|
||||||
}
|
}
|
||||||
|
|
@ -249,28 +249,26 @@ fn check_place(
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> McfResult {
|
) -> McfResult {
|
||||||
place.iterate(|place_base, place_projection| {
|
for elem in place.projection.iter() {
|
||||||
for proj in place_projection {
|
match elem {
|
||||||
match proj.elem {
|
ProjectionElem::Downcast(..) => {
|
||||||
ProjectionElem::Downcast(..) => {
|
return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
|
||||||
return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
|
|
||||||
}
|
|
||||||
ProjectionElem::ConstantIndex { .. }
|
|
||||||
| ProjectionElem::Subslice { .. }
|
|
||||||
| ProjectionElem::Deref
|
|
||||||
| ProjectionElem::Field(..)
|
|
||||||
| ProjectionElem::Index(_) => {}
|
|
||||||
}
|
}
|
||||||
|
ProjectionElem::ConstantIndex { .. }
|
||||||
|
| ProjectionElem::Subslice { .. }
|
||||||
|
| ProjectionElem::Deref
|
||||||
|
| ProjectionElem::Field(..)
|
||||||
|
| ProjectionElem::Index(_) => {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match place_base {
|
match place.base {
|
||||||
PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
|
PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
|
||||||
Err((span, "cannot access `static` items in const fn".into()))
|
Err((span, "cannot access `static` items in const fn".into()))
|
||||||
}
|
|
||||||
PlaceBase::Local(_)
|
|
||||||
| PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
|
|
||||||
}
|
}
|
||||||
})
|
PlaceBase::Local(_)
|
||||||
|
| PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_terminator(
|
fn check_terminator(
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ impl RemoveNoopLandingPads {
|
||||||
// These are all nops in a landing pad
|
// These are all nops in a landing pad
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementKind::Assign(Place {
|
StatementKind::Assign(box(Place {
|
||||||
base: PlaceBase::Local(_),
|
base: PlaceBase::Local(_),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}, box Rvalue::Use(_)) => {
|
}, Rvalue::Use(_))) => {
|
||||||
// Writing to a local (e.g., a drop flag) does not
|
// Writing to a local (e.g., a drop flag) does not
|
||||||
// turn a landing pad to a non-nop
|
// turn a landing pad to a non-nop
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,11 +120,11 @@ fn each_block<'tcx, O>(
|
||||||
let peek_arg_place = match args[0] {
|
let peek_arg_place = match args[0] {
|
||||||
mir::Operand::Copy(ref place @ mir::Place {
|
mir::Operand::Copy(ref place @ mir::Place {
|
||||||
base: mir::PlaceBase::Local(_),
|
base: mir::PlaceBase::Local(_),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) |
|
}) |
|
||||||
mir::Operand::Move(ref place @ mir::Place {
|
mir::Operand::Move(ref place @ mir::Place {
|
||||||
base: mir::PlaceBase::Local(_),
|
base: mir::PlaceBase::Local(_),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) => Some(place),
|
}) => Some(place),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
@ -150,7 +150,7 @@ fn each_block<'tcx, O>(
|
||||||
for (j, stmt) in statements.iter().enumerate() {
|
for (j, stmt) in statements.iter().enumerate() {
|
||||||
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
|
debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
|
||||||
let (place, rvalue) = match stmt.kind {
|
let (place, rvalue) = match stmt.kind {
|
||||||
mir::StatementKind::Assign(ref place, ref rvalue) => {
|
mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
|
||||||
(place, rvalue)
|
(place, rvalue)
|
||||||
}
|
}
|
||||||
mir::StatementKind::FakeRead(..) |
|
mir::StatementKind::FakeRead(..) |
|
||||||
|
|
@ -166,7 +166,7 @@ fn each_block<'tcx, O>(
|
||||||
};
|
};
|
||||||
|
|
||||||
if place == peek_arg_place {
|
if place == peek_arg_place {
|
||||||
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
|
if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = *rvalue {
|
||||||
// Okay, our search is over.
|
// Okay, our search is over.
|
||||||
match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
|
match move_data.rev_lookup.find(peeking_at_place.as_ref()) {
|
||||||
LookupResult::Exact(peek_mpi) => {
|
LookupResult::Exact(peek_mpi) => {
|
||||||
|
|
|
||||||
|
|
@ -61,14 +61,14 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
|
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
|
||||||
if let Some(ref proj) = src_place.projection {
|
if let box [proj_base @ .., elem] = &src_place.projection {
|
||||||
if let ProjectionElem::ConstantIndex{offset: _,
|
if let ProjectionElem::ConstantIndex{offset: _,
|
||||||
min_length: _,
|
min_length: _,
|
||||||
from_end: false} = proj.elem {
|
from_end: false} = elem {
|
||||||
// no need to transformation
|
// no need to transformation
|
||||||
} else {
|
} else {
|
||||||
let place_ty =
|
let place_ty =
|
||||||
Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).ty;
|
Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
|
||||||
if let ty::Array(item_ty, const_size) = place_ty.sty {
|
if let ty::Array(item_ty, const_size) = place_ty.sty {
|
||||||
if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
|
if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
|
||||||
assert!(size <= u32::max_value() as u64,
|
assert!(size <= u32::max_value() as u64,
|
||||||
|
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||||
location,
|
location,
|
||||||
dst_place,
|
dst_place,
|
||||||
&src_place.base,
|
&src_place.base,
|
||||||
proj,
|
&src_place.projection,
|
||||||
item_ty,
|
item_ty,
|
||||||
size as u32,
|
size as u32,
|
||||||
);
|
);
|
||||||
|
|
@ -97,73 +97,76 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||||
location: Location,
|
location: Location,
|
||||||
dst_place: &Place<'tcx>,
|
dst_place: &Place<'tcx>,
|
||||||
base: &PlaceBase<'tcx>,
|
base: &PlaceBase<'tcx>,
|
||||||
proj: &Projection<'tcx>,
|
proj: &[PlaceElem<'tcx>],
|
||||||
item_ty: &'tcx ty::TyS<'tcx>,
|
item_ty: &'tcx ty::TyS<'tcx>,
|
||||||
size: u32) {
|
size: u32) {
|
||||||
match proj.elem {
|
if let [proj_base @ .., elem] = proj {
|
||||||
// uniforms statements like_10 = move _2[:-1];
|
match elem {
|
||||||
ProjectionElem::Subslice{from, to} => {
|
// uniforms statements like_10 = move _2[:-1];
|
||||||
self.patch.make_nop(location);
|
ProjectionElem::Subslice{from, to} => {
|
||||||
let temps : Vec<_> = (from..(size-to)).map(|i| {
|
self.patch.make_nop(location);
|
||||||
let temp = self.patch.new_temp(item_ty, self.body.source_info(location).span);
|
let temps : Vec<_> = (*from..(size-*to)).map(|i| {
|
||||||
self.patch.add_statement(location, StatementKind::StorageLive(temp));
|
let temp =
|
||||||
|
self.patch.new_temp(item_ty, self.body.source_info(location).span);
|
||||||
|
self.patch.add_statement(location, StatementKind::StorageLive(temp));
|
||||||
|
|
||||||
|
let mut projection = proj_base.to_vec();
|
||||||
|
projection.push(ProjectionElem::ConstantIndex {
|
||||||
|
offset: i,
|
||||||
|
min_length: size,
|
||||||
|
from_end: false,
|
||||||
|
});
|
||||||
|
self.patch.add_assign(location,
|
||||||
|
Place::from(temp),
|
||||||
|
Rvalue::Use(
|
||||||
|
Operand::Move(
|
||||||
|
Place {
|
||||||
|
base: base.clone(),
|
||||||
|
projection: projection.into_boxed_slice(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
temp
|
||||||
|
}).collect();
|
||||||
|
self.patch.add_assign(
|
||||||
|
location,
|
||||||
|
dst_place.clone(),
|
||||||
|
Rvalue::Aggregate(
|
||||||
|
box AggregateKind::Array(item_ty),
|
||||||
|
temps.iter().map(
|
||||||
|
|x| Operand::Move(Place::from(*x))
|
||||||
|
).collect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for temp in temps {
|
||||||
|
self.patch.add_statement(location, StatementKind::StorageDead(temp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// uniforms statements like _11 = move _2[-1 of 1];
|
||||||
|
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
|
||||||
|
self.patch.make_nop(location);
|
||||||
|
|
||||||
|
let mut projection = proj_base.to_vec();
|
||||||
|
projection.push(ProjectionElem::ConstantIndex {
|
||||||
|
offset: size - offset,
|
||||||
|
min_length: size,
|
||||||
|
from_end: false,
|
||||||
|
});
|
||||||
self.patch.add_assign(location,
|
self.patch.add_assign(location,
|
||||||
Place::from(temp),
|
dst_place.clone(),
|
||||||
Rvalue::Use(
|
Rvalue::Use(
|
||||||
Operand::Move(
|
Operand::Move(
|
||||||
Place {
|
Place {
|
||||||
base: base.clone(),
|
base: base.clone(),
|
||||||
projection: Some(box Projection {
|
projection: projection.into_boxed_slice(),
|
||||||
base: proj.base.clone(),
|
|
||||||
elem: ProjectionElem::ConstantIndex {
|
|
||||||
offset: i,
|
|
||||||
min_length: size,
|
|
||||||
from_end: false,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
temp
|
|
||||||
}).collect();
|
|
||||||
self.patch.add_assign(
|
|
||||||
location,
|
|
||||||
dst_place.clone(),
|
|
||||||
Rvalue::Aggregate(
|
|
||||||
box AggregateKind::Array(item_ty),
|
|
||||||
temps.iter().map(
|
|
||||||
|x| Operand::Move(Place::from(*x))
|
|
||||||
).collect()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
for temp in temps {
|
|
||||||
self.patch.add_statement(location, StatementKind::StorageDead(temp));
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
// uniforms statements like _11 = move _2[-1 of 1];
|
|
||||||
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
|
|
||||||
self.patch.make_nop(location);
|
|
||||||
self.patch.add_assign(location,
|
|
||||||
dst_place.clone(),
|
|
||||||
Rvalue::Use(
|
|
||||||
Operand::Move(
|
|
||||||
Place {
|
|
||||||
base: base.clone(),
|
|
||||||
projection: Some(box Projection {
|
|
||||||
base: proj.base.clone(),
|
|
||||||
elem: ProjectionElem::ConstantIndex {
|
|
||||||
offset: size - offset,
|
|
||||||
min_length: size,
|
|
||||||
from_end: false,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,12 +200,12 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
||||||
|
|
||||||
for candidate in &visitor.candidates {
|
for candidate in &visitor.candidates {
|
||||||
let statement = &body[candidate.block].statements[candidate.statement_index];
|
let statement = &body[candidate.block].statements[candidate.statement_index];
|
||||||
if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
|
if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
|
||||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = **rval {
|
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
|
||||||
let items : Vec<_> = items.iter().map(|item| {
|
let items : Vec<_> = items.iter().map(|item| {
|
||||||
if let Operand::Move(Place {
|
if let Operand::Move(Place {
|
||||||
base: PlaceBase::Local(local),
|
base: PlaceBase::Local(local),
|
||||||
projection: None,
|
projection: box [],
|
||||||
}) = item {
|
}) = item {
|
||||||
let local_use = &visitor.locals_use[*local];
|
let local_use = &visitor.locals_use[*local];
|
||||||
let opt_index_and_place =
|
let opt_index_and_place =
|
||||||
|
|
@ -269,16 +272,17 @@ impl RestoreSubsliceArrayMoveOut {
|
||||||
}
|
}
|
||||||
patch.make_nop(candidate);
|
patch.make_nop(candidate);
|
||||||
let size = opt_size.unwrap() as u32;
|
let size = opt_size.unwrap() as u32;
|
||||||
patch.add_assign(candidate,
|
|
||||||
dst_place.clone(),
|
let mut projection = src_place.projection.to_vec();
|
||||||
Rvalue::Use(
|
projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
|
||||||
Operand::Move(
|
patch.add_assign(
|
||||||
Place {
|
candidate,
|
||||||
base: src_place.base.clone(),
|
dst_place.clone(),
|
||||||
projection: Some(box Projection {
|
Rvalue::Use(Operand::Move(Place {
|
||||||
base: src_place.projection.clone(),
|
base: src_place.base.clone(),
|
||||||
elem: ProjectionElem::Subslice{
|
projection: projection.into_boxed_slice(),
|
||||||
from: min, to: size - max - 1}})})));
|
})),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,23 +293,34 @@ impl RestoreSubsliceArrayMoveOut {
|
||||||
if block.statements.len() > location.statement_index {
|
if block.statements.len() > location.statement_index {
|
||||||
let statement = &block.statements[location.statement_index];
|
let statement = &block.statements[location.statement_index];
|
||||||
if let StatementKind::Assign(
|
if let StatementKind::Assign(
|
||||||
Place {
|
box(
|
||||||
base: PlaceBase::Local(_),
|
Place {
|
||||||
projection: None,
|
base: PlaceBase::Local(_),
|
||||||
},
|
projection: box [],
|
||||||
box Rvalue::Use(Operand::Move(Place {
|
},
|
||||||
base,
|
Rvalue::Use(Operand::Move(Place {
|
||||||
projection: Some(box Projection {
|
base: _,
|
||||||
base: proj_base,
|
projection: box [.., ProjectionElem::ConstantIndex {
|
||||||
elem: ProjectionElem::ConstantIndex {
|
|
||||||
offset, min_length: _, from_end: false
|
offset, min_length: _, from_end: false
|
||||||
}
|
}],
|
||||||
}),
|
})),
|
||||||
}))) = &statement.kind {
|
)
|
||||||
return Some((*offset, PlaceRef {
|
) = &statement.kind {
|
||||||
base,
|
// FIXME remove once we can use slices patterns
|
||||||
projection: proj_base,
|
if let StatementKind::Assign(
|
||||||
}))
|
box(
|
||||||
|
_,
|
||||||
|
Rvalue::Use(Operand::Move(Place {
|
||||||
|
base,
|
||||||
|
projection: box [proj_base @ .., _],
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
) = &statement.kind {
|
||||||
|
return Some((*offset, PlaceRef {
|
||||||
|
base,
|
||||||
|
projection: proj_base,
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ pub fn expand_aggregate<'tcx>(
|
||||||
if adt_def.is_enum() {
|
if adt_def.is_enum() {
|
||||||
set_discriminant = Some(Statement {
|
set_discriminant = Some(Statement {
|
||||||
kind: StatementKind::SetDiscriminant {
|
kind: StatementKind::SetDiscriminant {
|
||||||
place: lhs.clone(),
|
place: box(lhs.clone()),
|
||||||
variant_index,
|
variant_index,
|
||||||
},
|
},
|
||||||
source_info,
|
source_info,
|
||||||
|
|
@ -39,7 +39,7 @@ pub fn expand_aggregate<'tcx>(
|
||||||
let variant_index = VariantIdx::new(0);
|
let variant_index = VariantIdx::new(0);
|
||||||
set_discriminant = Some(Statement {
|
set_discriminant = Some(Statement {
|
||||||
kind: StatementKind::SetDiscriminant {
|
kind: StatementKind::SetDiscriminant {
|
||||||
place: lhs.clone(),
|
place: box(lhs.clone()),
|
||||||
variant_index,
|
variant_index,
|
||||||
},
|
},
|
||||||
source_info,
|
source_info,
|
||||||
|
|
@ -70,7 +70,7 @@ pub fn expand_aggregate<'tcx>(
|
||||||
};
|
};
|
||||||
Statement {
|
Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
|
kind: StatementKind::Assign(box(lhs_field, Rvalue::Use(op))),
|
||||||
}
|
}
|
||||||
}).chain(set_discriminant)
|
}).chain(set_discriminant)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
|
||||||
where
|
where
|
||||||
L: HasLocalDecls<'tcx>,
|
L: HasLocalDecls<'tcx>,
|
||||||
{
|
{
|
||||||
let mut place_projection = &place.projection;
|
for (i, elem) in place.projection.iter().enumerate().rev() {
|
||||||
|
let proj_base = &place.projection[..i];
|
||||||
|
|
||||||
while let Some(proj) = place_projection {
|
match elem {
|
||||||
match proj.elem {
|
|
||||||
// encountered a Deref, which is ABI-aligned
|
// encountered a Deref, which is ABI-aligned
|
||||||
ProjectionElem::Deref => break,
|
ProjectionElem::Deref => break,
|
||||||
ProjectionElem::Field(..) => {
|
ProjectionElem::Field(..) => {
|
||||||
let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty;
|
let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Adt(def, _) if def.repr.packed() => {
|
ty::Adt(def, _) if def.repr.packed() => {
|
||||||
return true
|
return true
|
||||||
|
|
@ -55,7 +55,6 @@ where
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
place_projection = &proj.base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
|
|
|
||||||
|
|
@ -586,10 +586,7 @@ where
|
||||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||||
Place {
|
Place {
|
||||||
base: PlaceBase::Local(cur),
|
base: PlaceBase::Local(cur),
|
||||||
projection: Some(Box::new(Projection {
|
projection: Box::new([ProjectionElem::Deref]),
|
||||||
base: None,
|
|
||||||
elem: ProjectionElem::Deref,
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
|
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
|
||||||
|
|
@ -981,7 +978,7 @@ where
|
||||||
fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
|
fn assign(&self, lhs: &Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
|
||||||
Statement {
|
Statement {
|
||||||
source_info: self.source_info,
|
source_info: self.source_info,
|
||||||
kind: StatementKind::Assign(lhs.clone(), box rhs)
|
kind: StatementKind::Assign(box(lhs.clone(), rhs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ impl<'tcx> MirPatch<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
|
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
|
||||||
self.add_statement(loc, StatementKind::Assign(place, box rv));
|
self.add_statement(loc, StatementKind::Assign(box(place, rv)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_nop(&mut self, loc: Location) {
|
pub fn make_nop(&mut self, loc: Location) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue