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

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

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

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

View file

@ -32,7 +32,6 @@ use rustc_serialize::{Encodable, Decodable};
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write};
use std::iter::FusedIterator;
use std::ops::{Index, IndexMut};
use std::slice;
use std::vec::IntoIter;
@ -1548,7 +1547,7 @@ pub struct Statement<'tcx> {
// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(Statement<'_>, 56);
static_assert_size!(Statement<'_>, 32);
impl Statement<'_> {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@ -1569,7 +1568,7 @@ impl Statement<'_> {
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
pub enum StatementKind<'tcx> {
/// Write the RHS Rvalue to the LHS Place.
Assign(Place<'tcx>, Box<Rvalue<'tcx>>),
Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
/// This represents all the reading that a pattern match may do
/// (e.g., inspecting constants and discriminant values), and the
@ -1578,10 +1577,10 @@ pub enum StatementKind<'tcx> {
///
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
FakeRead(FakeReadCause, Place<'tcx>),
FakeRead(FakeReadCause, Box<Place<'tcx>>),
/// Write the discriminant for a variant to the enum Place.
SetDiscriminant { place: Place<'tcx>, variant_index: VariantIdx },
SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
/// Start a live range for the storage of the local.
StorageLive(Local),
@ -1598,7 +1597,7 @@ pub enum StatementKind<'tcx> {
/// by miri and only generated when "-Z mir-emit-retag" is passed.
/// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
/// for more details.
Retag(RetagKind, Place<'tcx>),
Retag(RetagKind, Box<Place<'tcx>>),
/// Encodes a user's type ascription. These need to be preserved
/// intact so that NLL can respect them. For example:
@ -1612,7 +1611,7 @@ pub enum StatementKind<'tcx> {
/// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect
AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>),
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
@ -1676,7 +1675,7 @@ impl Debug for Statement<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
use self::StatementKind::*;
match self.kind {
Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv),
Assign(box(ref place, ref rv)) => write!(fmt, "{:?} = {:?}", place, rv),
FakeRead(ref cause, ref place) => write!(fmt, "FakeRead({:?}, {:?})", cause, place),
Retag(ref kind, ref place) => write!(
fmt,
@ -1697,7 +1696,7 @@ impl Debug for Statement<'_> {
InlineAsm(ref asm) => {
write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
}
AscribeUserType(ref place, ref variance, ref c_ty) => {
AscribeUserType(box(ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}
Nop => write!(fmt, "nop"),
@ -1717,7 +1716,7 @@ pub struct Place<'tcx> {
pub base: PlaceBase<'tcx>,
/// projection out of a place (access a field, deref a pointer, etc)
pub projection: Option<Box<Projection<'tcx>>>,
pub projection: Box<[PlaceElem<'tcx>]>,
}
#[derive(
@ -1760,15 +1759,6 @@ impl_stable_hash_for!(struct Static<'tcx> {
def_id
});
/// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`.
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)]
pub struct Projection<'tcx> {
pub base: Option<Box<Projection<'tcx>>>,
pub elem: PlaceElem<'tcx>,
}
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)]
@ -1850,14 +1840,22 @@ newtype_index! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlaceRef<'a, 'tcx> {
pub base: &'a PlaceBase<'tcx>,
pub projection: &'a Option<Box<Projection<'tcx>>>,
pub projection: &'a [PlaceElem<'tcx>],
}
impl<'tcx> Place<'tcx> {
pub const RETURN_PLACE: Place<'tcx> = Place {
base: PlaceBase::Local(RETURN_PLACE),
projection: None,
};
// FIXME change this back to a const when projection is a shared slice.
//
// pub const RETURN_PLACE: Place<'tcx> = Place {
// base: PlaceBase::Local(RETURN_PLACE),
// projection: &[],
// };
pub fn return_place() -> Place<'tcx> {
Place {
base: PlaceBase::Local(RETURN_PLACE),
projection: Box::new([]),
}
}
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
self.elem(ProjectionElem::Field(f, ty))
@ -1883,9 +1881,13 @@ impl<'tcx> Place<'tcx> {
}
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
// FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
let mut projection = self.projection.into_vec();
projection.push(elem);
Place {
base: self.base,
projection: Some(Box::new(Projection { base: self.projection, elem })),
projection: projection.into_boxed_slice(),
}
}
@ -1894,7 +1896,7 @@ impl<'tcx> Place<'tcx> {
/// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
/// same region of memory as its base.
pub fn is_indirect(&self) -> bool {
self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect()))
self.projection.iter().any(|elem| elem.is_indirect())
}
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
@ -1905,61 +1907,16 @@ impl<'tcx> Place<'tcx> {
match self {
Place {
base: PlaceBase::Local(local),
projection: None,
projection: box [],
} |
Place {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
}),
projection: box [ProjectionElem::Deref],
} => Some(*local),
_ => None,
}
}
/// Recursively "iterates" over place components, generating a `PlaceBase` and
/// `Projections` list and invoking `op` with a `ProjectionsIter`.
pub fn iterate<R>(
&self,
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
) -> R {
Place::iterate_over(&self.base, &self.projection, op)
}
pub fn iterate_over<R>(
place_base: &PlaceBase<'tcx>,
place_projection: &Option<Box<Projection<'tcx>>>,
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
) -> R {
fn iterate_over2<'tcx, R>(
place_base: &PlaceBase<'tcx>,
place_projection: &Option<Box<Projection<'tcx>>>,
next: &Projections<'_, 'tcx>,
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
) -> R {
match place_projection {
None => {
op(place_base, next.iter())
}
Some(interior) => {
iterate_over2(
place_base,
&interior.base,
&Projections::List {
projection: interior,
next,
},
op,
)
}
}
}
iterate_over2(place_base, place_projection, &Projections::Empty, op)
}
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
PlaceRef {
base: &self.base,
@ -1972,7 +1929,7 @@ impl From<Local> for Place<'_> {
fn from(local: Local) -> Self {
Place {
base: local.into(),
projection: None,
projection: Box::new([]),
}
}
}
@ -1984,13 +1941,6 @@ impl From<Local> for PlaceBase<'_> {
}
impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
pub fn iterate<R>(
&self,
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
) -> R {
Place::iterate_over(self.base, self.projection, op)
}
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local.
//
@ -1999,143 +1949,71 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
match self {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
projection: [],
} |
PlaceRef {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
}),
projection: [ProjectionElem::Deref],
} => Some(*local),
_ => None,
}
}
}
/// A linked list of projections running up the stack; begins with the
/// innermost projection and extends to the outermost (e.g., `a.b.c`
/// would have the place `b` with a "next" pointer to `b.c`).
/// Created by `Place::iterate`.
///
/// N.B., this particular impl strategy is not the most obvious. It was
/// chosen because it makes a measurable difference to NLL
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
pub enum Projections<'p, 'tcx> {
Empty,
List { projection: &'p Projection<'tcx>, next: &'p Projections<'p, 'tcx> },
}
impl<'p, 'tcx> Projections<'p, 'tcx> {
fn iter(&self) -> ProjectionsIter<'_, 'tcx> {
ProjectionsIter { value: self }
}
}
impl<'p, 'tcx> IntoIterator for &'p Projections<'p, 'tcx> {
type Item = &'p Projection<'tcx>;
type IntoIter = ProjectionsIter<'p, 'tcx>;
/// Converts a list of `Projection` components into an iterator;
/// this iterator yields up a never-ending stream of `Option<&Place>`.
/// These begin with the "innermost" projection and then with each
/// projection therefrom. So given a place like `a.b.c` it would
/// yield up:
///
/// ```notrust
/// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
/// ```
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// Iterator over components; see `Projections::iter` for more
/// information.
///
/// N.B., this is not a *true* Rust iterator -- the code above just
/// manually invokes `next`. This is because we (sometimes) want to
/// keep executing even after `None` has been returned.
pub struct ProjectionsIter<'p, 'tcx> {
pub value: &'p Projections<'p, 'tcx>,
}
impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> {
type Item = &'p Projection<'tcx>;
fn next(&mut self) -> Option<Self::Item> {
if let &Projections::List { projection, next } = self.value {
self.value = next;
Some(projection)
} else {
None
}
}
}
impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {}
impl Debug for Place<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.iterate(|_place_base, place_projections| {
// FIXME: remove this collect once we have migrated to slices
let projs_vec: Vec<_> = place_projections.collect();
for projection in projs_vec.iter().rev() {
match projection.elem {
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap();
}
ProjectionElem::Deref => {
write!(fmt, "(*").unwrap();
}
ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {}
for elem in self.projection.iter().rev() {
match elem {
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap();
}
ProjectionElem::Deref => {
write!(fmt, "(*").unwrap();
}
ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {}
}
}
write!(fmt, "{:?}", self.base)?;
for elem in self.projection.iter() {
match elem {
ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {})", name)?;
}
ProjectionElem::Downcast(None, index) => {
write!(fmt, " as variant#{:?})", index)?;
}
ProjectionElem::Deref => {
write!(fmt, ")")?;
}
ProjectionElem::Field(field, ty) => {
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
}
ProjectionElem::Index(ref index) => {
write!(fmt, "[{:?}]", index)?;
}
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
}
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
}
ProjectionElem::Subslice { from, to } if *to == 0 => {
write!(fmt, "[{:?}:]", from)?;
}
ProjectionElem::Subslice { from, to } if *from == 0 => {
write!(fmt, "[:-{:?}]", to)?;
}
ProjectionElem::Subslice { from, to } => {
write!(fmt, "[{:?}:-{:?}]", from, to)?;
}
}
});
}
self.iterate(|place_base, place_projections| {
write!(fmt, "{:?}", place_base)?;
for projection in place_projections {
match projection.elem {
ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {})", name)?;
}
ProjectionElem::Downcast(None, index) => {
write!(fmt, " as variant#{:?})", index)?;
}
ProjectionElem::Deref => {
write!(fmt, ")")?;
}
ProjectionElem::Field(field, ty) => {
write!(fmt, ".{:?}: {:?})", field.index(), ty)?;
}
ProjectionElem::Index(ref index) => {
write!(fmt, "[{:?}]", index)?;
}
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => {
write!(fmt, "[{:?} of {:?}]", offset, min_length)?;
}
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
}
ProjectionElem::Subslice { from, to } if to == 0 => {
write!(fmt, "[{:?}:]", from)?;
}
ProjectionElem::Subslice { from, to } if from == 0 => {
write!(fmt, "[:-{:?}]", to)?;
}
ProjectionElem::Subslice { from, to } => {
write!(fmt, "[{:?}:-{:?}]", from, to)?;
}
}
}
Ok(())
})
Ok(())
}
}
@ -3120,14 +2998,14 @@ BraceStructTypeFoldableImpl! {
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
(StatementKind::Assign)(a, b),
(StatementKind::Assign)(a),
(StatementKind::FakeRead)(cause, place),
(StatementKind::SetDiscriminant) { place, variant_index },
(StatementKind::StorageLive)(a),
(StatementKind::StorageDead)(a),
(StatementKind::InlineAsm)(a),
(StatementKind::Retag)(kind, place),
(StatementKind::AscribeUserType)(a, v, b),
(StatementKind::AscribeUserType)(a, v),
(StatementKind::Nop),
}
}
@ -3409,30 +3287,26 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for Projection<'tcx> {
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
use crate::mir::ProjectionElem::*;
let base = self.base.fold_with(folder);
let elem = match self.elem {
match self {
Deref => Deref,
Field(f, ref ty) => Field(f, ty.fold_with(folder)),
Index(ref v) => Index(v.fold_with(folder)),
ref elem => elem.clone(),
};
Projection { base, elem }
Field(f, ty) => Field(*f, ty.fold_with(folder)),
Index(v) => Index(v.fold_with(folder)),
elem => elem.clone(),
}
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
use crate::mir::ProjectionElem::*;
self.base.visit_with(visitor)
|| match self.elem {
Field(_, ref ty) => ty.visit_with(visitor),
Index(ref v) => v.visit_with(visitor),
_ => false,
}
match self {
Field(_, ty) => ty.visit_with(visitor),
Index(v) => v.visit_with(visitor),
_ => false,
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -384,47 +384,45 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> Option<OperandRef<'tcx, Bx::Value>> {
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
place_ref.iterate(|place_base, place_projection| {
if let mir::PlaceBase::Local(index) = place_base {
match self.locals[*index] {
LocalRef::Operand(Some(mut o)) => {
// Moves out of scalar and scalar pair fields are trivial.
for proj in place_projection {
match proj.elem {
mir::ProjectionElem::Field(ref f, _) => {
o = o.extract_field(bx, f.index());
}
mir::ProjectionElem::Index(_) |
mir::ProjectionElem::ConstantIndex { .. } => {
// ZSTs don't require any actual memory access.
// FIXME(eddyb) deduplicate this with the identical
// checks in `codegen_consume` and `extract_field`.
let elem = o.layout.field(bx.cx(), 0);
if elem.is_zst() {
o = OperandRef::new_zst(bx, elem);
} else {
return None;
}
}
_ => return None,
if let mir::PlaceBase::Local(index) = place_ref.base {
match self.locals[*index] {
LocalRef::Operand(Some(mut o)) => {
// Moves out of scalar and scalar pair fields are trivial.
for elem in place_ref.projection.iter() {
match elem {
mir::ProjectionElem::Field(ref f, _) => {
o = o.extract_field(bx, f.index());
}
mir::ProjectionElem::Index(_) |
mir::ProjectionElem::ConstantIndex { .. } => {
// ZSTs don't require any actual memory access.
// FIXME(eddyb) deduplicate this with the identical
// checks in `codegen_consume` and `extract_field`.
let elem = o.layout.field(bx.cx(), 0);
if elem.is_zst() {
o = OperandRef::new_zst(bx, elem);
} else {
return None;
}
}
_ => return None,
}
}
Some(o)
}
LocalRef::Operand(None) => {
bug!("use of {:?} before def", place_ref);
}
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
// watch out for locals that do not have an
// alloca; they are handled somewhat differently
None
}
Some(o)
}
LocalRef::Operand(None) => {
bug!("use of {:?} before def", place_ref);
}
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
// watch out for locals that do not have an
// alloca; they are handled somewhat differently
None
}
} else {
None
}
})
} else {
None
}
}
pub fn codegen_consume(

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,8 +3,7 @@ use crate::borrow_check::Overlap;
use crate::borrow_check::{Deep, Shallow, AccessDepth};
use rustc::hir;
use rustc::mir::{
Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
StaticKind,
Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
};
use rustc::ty::{self, TyCtxt};
use std::cmp::max;
@ -67,39 +66,35 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
// it's so common that it's a speed win to check for it first.
if let Place {
base: PlaceBase::Local(l1),
projection: None,
projection: box [],
} = borrow_place {
if let PlaceRef {
base: PlaceBase::Local(l2),
projection: None,
projection: [],
} = access_place {
return l1 == l2;
}
}
borrow_place.iterate(|borrow_base, borrow_projections| {
access_place.iterate(|access_base, access_projections| {
place_components_conflict(
tcx,
param_env,
body,
(borrow_base, borrow_projections),
borrow_kind,
(access_base, access_projections),
access,
bias,
)
})
})
place_components_conflict(
tcx,
param_env,
body,
borrow_place,
borrow_kind,
access_place,
access,
bias,
)
}
fn place_components_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
borrow_place: &Place<'tcx>,
borrow_kind: BorrowKind,
access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
access_place: PlaceRef<'_, 'tcx>,
access: AccessDepth,
bias: PlaceConflictBias,
) -> bool {
@ -145,8 +140,8 @@ fn place_components_conflict<'tcx>(
// and either equal or disjoint.
// - If we did run out of access, the borrow can access a part of it.
let borrow_base = borrow_projections.0;
let access_base = access_projections.0;
let borrow_base = &borrow_place.base;
let access_base = access_place.base;
match place_base_conflict(tcx, param_env, borrow_base, access_base) {
Overlap::Arbitrary => {
@ -163,147 +158,157 @@ fn place_components_conflict<'tcx>(
}
}
let mut borrow_projections = borrow_projections.1;
let mut access_projections = access_projections.1;
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
for (i, (borrow_c, access_c)) in
borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate()
{
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
let borrow_proj_base = &borrow_place.projection[..i];
loop {
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
if let Some(borrow_c) = borrow_projections.next() {
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
if let Some(access_c) = access_projections.next() {
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
// Borrow and access path both have more components.
// Borrow and access path both have more components.
//
// Examples:
//
// - borrow of `a.(...)`, access to `a.(...)`
// - borrow of `a.(...)`, access to `b.(...)`
//
// Here we only see the components we have checked so
// far (in our examples, just the first component). We
// check whether the components being borrowed vs
// accessed are disjoint (as in the second example,
// but not the first).
match place_projection_conflict(
tcx,
body,
borrow_base,
borrow_proj_base,
borrow_c,
access_c,
bias,
) {
Overlap::Arbitrary => {
// We have encountered different fields of potentially
// the same union - the borrow now partially overlaps.
//
// Examples:
// There is no *easy* way of comparing the fields
// further on, because they might have different types
// (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
// `.y` come from different structs).
//
// - borrow of `a.(...)`, access to `a.(...)`
// - borrow of `a.(...)`, access to `b.(...)`
//
// Here we only see the components we have checked so
// far (in our examples, just the first component). We
// check whether the components being borrowed vs
// accessed are disjoint (as in the second example,
// but not the first).
match place_projection_conflict(tcx, body, borrow_base, borrow_c, access_c, bias) {
Overlap::Arbitrary => {
// We have encountered different fields of potentially
// the same union - the borrow now partially overlaps.
//
// There is no *easy* way of comparing the fields
// further on, because they might have different types
// (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
// `.y` come from different structs).
//
// We could try to do some things here - e.g., count
// dereferences - but that's probably not a good
// idea, at least for now, so just give up and
// report a conflict. This is unsafe code anyway so
// the user could always use raw pointers.
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
return true;
}
Overlap::EqualOrDisjoint => {
// This is the recursive case - proceed to the next element.
}
Overlap::Disjoint => {
// We have proven the borrow disjoint - further
// projections will remain disjoint.
debug!("borrow_conflicts_with_place: disjoint");
return false;
}
}
} else {
// Borrow path is longer than the access path. Examples:
//
// - borrow of `a.b.c`, access to `a.b`
//
// Here, we know that the borrow can access a part of
// our place. This is a conflict if that is a part our
// access cares about.
let base = &borrow_c.base;
let elem = &borrow_c.elem;
let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty;
match (elem, &base_ty.sty, access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
// The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any
// borrowed place (at least in MIR as it is currently.)
//
// e.g., a (mutable) borrow of `a[5]` while we read the
// array length of `a`.
debug!("borrow_conflicts_with_place: implicit field");
return false;
}
(ProjectionElem::Deref, _, Shallow(None)) => {
// e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
// prefix thereof - the shallow access can't touch anything behind
// the pointer.
debug!("borrow_conflicts_with_place: shallow access behind ptr");
return false;
}
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
// Shouldn't be tracked
bug!("Tracking borrow behind shared reference.");
}
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
// Values behind a mutable reference are not access either by dropping a
// value, or by StorageDead
debug!("borrow_conflicts_with_place: drop access behind ptr");
return false;
}
(ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
// Drop can read/write arbitrary projections, so places
// conflict regardless of further projections.
if def.has_dtor(tcx) {
return true;
}
}
(ProjectionElem::Deref, _, Deep)
| (ProjectionElem::Deref, _, AccessDepth::Drop)
| (ProjectionElem::Field { .. }, _, _)
| (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
// there's a deref later on, e.g., a borrow
// of `*x.y` while accessing `x`.
}
}
}
} else {
// Borrow path ran out but access path may not
// have. Examples:
//
// - borrow of `a.b`, access to `a.b.c`
// - borrow of `a.b`, access to `a.b`
//
// In the first example, where we didn't run out of
// access, the borrow can access all of our place, so we
// have a conflict.
//
// If the second example, where we did, then we still know
// that the borrow can access a *part* of our place that
// our access cares about, so we still have a conflict.
if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() {
debug!("borrow_conflicts_with_place: shallow borrow");
return false;
} else {
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
// We could try to do some things here - e.g., count
// dereferences - but that's probably not a good
// idea, at least for now, so just give up and
// report a conflict. This is unsafe code anyway so
// the user could always use raw pointers.
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
return true;
}
Overlap::EqualOrDisjoint => {
// This is the recursive case - proceed to the next element.
}
Overlap::Disjoint => {
// We have proven the borrow disjoint - further
// projections will remain disjoint.
debug!("borrow_conflicts_with_place: disjoint");
return false;
}
}
}
if borrow_place.projection.len() > access_place.projection.len() {
for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
{
// Borrow path is longer than the access path. Examples:
//
// - borrow of `a.b.c`, access to `a.b`
//
// Here, we know that the borrow can access a part of
// our place. This is a conflict if that is a part our
// access cares about.
let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
match (elem, &base_ty.sty, access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
// The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any
// borrowed place (at least in MIR as it is currently.)
//
// e.g., a (mutable) borrow of `a[5]` while we read the
// array length of `a`.
debug!("borrow_conflicts_with_place: implicit field");
return false;
}
(ProjectionElem::Deref, _, Shallow(None)) => {
// e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
// prefix thereof - the shallow access can't touch anything behind
// the pointer.
debug!("borrow_conflicts_with_place: shallow access behind ptr");
return false;
}
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
// Shouldn't be tracked
bug!("Tracking borrow behind shared reference.");
}
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
// Values behind a mutable reference are not access either by dropping a
// value, or by StorageDead
debug!("borrow_conflicts_with_place: drop access behind ptr");
return false;
}
(ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
// Drop can read/write arbitrary projections, so places
// conflict regardless of further projections.
if def.has_dtor(tcx) {
return true;
}
}
(ProjectionElem::Deref, _, Deep)
| (ProjectionElem::Deref, _, AccessDepth::Drop)
| (ProjectionElem::Field { .. }, _, _)
| (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
// there's a deref later on, e.g., a borrow
// of `*x.y` while accessing `x`.
}
}
}
}
// Borrow path ran out but access path may not
// have. Examples:
//
// - borrow of `a.b`, access to `a.b.c`
// - borrow of `a.b`, access to `a.b`
//
// In the first example, where we didn't run out of
// access, the borrow can access all of our place, so we
// have a conflict.
//
// If the second example, where we did, then we still know
// that the borrow can access a *part* of our place that
// our access cares about, so we still have a conflict.
if borrow_kind == BorrowKind::Shallow
&& borrow_place.projection.len() < access_place.projection.len()
{
debug!("borrow_conflicts_with_place: shallow borrow");
false
} else {
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
true
}
}
// Given that the bases of `elem1` and `elem2` are always either equal
@ -381,11 +386,12 @@ fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pi1_base: &PlaceBase<'tcx>,
pi1: &Projection<'tcx>,
pi2: &Projection<'tcx>,
pi1_proj_base: &[PlaceElem<'tcx>],
pi1_elem: &PlaceElem<'tcx>,
pi2_elem: &PlaceElem<'tcx>,
bias: PlaceConflictBias,
) -> Overlap {
match (&pi1.elem, &pi2.elem) {
match (pi1_elem, pi2_elem) {
(ProjectionElem::Deref, ProjectionElem::Deref) => {
// derefs (e.g., `*x` vs. `*x`) - recur.
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
@ -397,7 +403,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint
} else {
let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty;
let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
match ty.sty {
ty::Adt(def, _) if def.is_union() => {
// Different fields of a union, we are basically stuck.
@ -493,7 +499,7 @@ fn place_projection_conflict<'tcx>(
// element (like -1 in Python) and `min_length` the first.
// Therefore, `min_length - offset_from_end` gives the minimal possible
// offset from the beginning
if *offset_from_begin >= min_length - offset_from_end {
if *offset_from_begin >= *min_length - *offset_from_end {
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
Overlap::EqualOrDisjoint
} else {
@ -538,8 +544,8 @@ fn place_projection_conflict<'tcx>(
| (ProjectionElem::Subslice { .. }, _)
| (ProjectionElem::Downcast(..), _) => bug!(
"mismatched projections in place_element_conflict: {:?} and {:?}",
pi1,
pi2
pi1_elem,
pi2_elem
),
}
}

View file

@ -19,17 +19,9 @@ pub trait IsPrefixOf<'cx, 'tcx> {
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
let mut cursor = other.projection;
loop {
if self.projection == cursor {
return self.base == other.base;
}
match cursor {
None => return false,
Some(proj) => cursor = &proj.base,
}
}
self.base == other.base
&& self.projection.len() <= other.projection.len()
&& self.projection == &other.projection[..self.projection.len()]
}
}
@ -81,112 +73,113 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
// downcasts here, but may return a base of a downcast).
'cursor: loop {
let proj = match &cursor {
match &cursor {
PlaceRef {
base: PlaceBase::Local(_),
projection: None,
projection: [],
}
| // search yielded this leaf
PlaceRef {
base: PlaceBase::Static(_),
projection: None,
projection: [],
} => {
self.next = None;
return Some(cursor);
}
PlaceRef {
base: _,
projection: Some(proj),
} => proj,
};
projection: [proj_base @ .., elem],
} => {
match elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
// FIXME: add union handling
self.next = Some(PlaceRef {
base: cursor.base,
projection: proj_base,
});
return Some(cursor);
}
ProjectionElem::Downcast(..) |
ProjectionElem::Subslice { .. } |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Index(_) => {
cursor = PlaceRef {
base: cursor.base,
projection: proj_base,
};
continue 'cursor;
}
ProjectionElem::Deref => {
// (handled below)
}
}
match proj.elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
// FIXME: add union handling
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}
ProjectionElem::Downcast(..) |
ProjectionElem::Subslice { .. } |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Index(_) => {
cursor = PlaceRef {
base: cursor.base,
projection: &proj.base,
};
continue 'cursor;
}
ProjectionElem::Deref => {
// (handled below)
}
}
assert_eq!(*elem, ProjectionElem::Deref);
assert_eq!(proj.elem, ProjectionElem::Deref);
match self.kind {
PrefixSet::Shallow => {
// Shallow prefixes are found by stripping away
// fields, but stop at *any* dereference.
// So we can just stop the traversal now.
self.next = None;
return Some(cursor);
}
PrefixSet::All => {
// All prefixes: just blindly enqueue the base
// of the projection.
self.next = Some(PlaceRef {
base: cursor.base,
projection: proj_base,
});
return Some(cursor);
}
PrefixSet::Supporting => {
// Fall through!
}
}
match self.kind {
PrefixSet::Shallow => {
// shallow prefixes are found by stripping away
// fields, but stop at *any* dereference.
// So we can just stop the traversal now.
self.next = None;
return Some(cursor);
}
PrefixSet::All => {
// all prefixes: just blindly enqueue the base
// of the projection.
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}
PrefixSet::Supporting => {
// fall through!
}
}
assert_eq!(self.kind, PrefixSet::Supporting);
// Supporting prefixes: strip away fields and
// derefs, except we stop at the deref of a shared
// reference.
assert_eq!(self.kind, PrefixSet::Supporting);
// supporting prefixes: strip away fields and
// derefs, except we stop at the deref of a shared
// reference.
let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty;
match ty.sty {
ty::RawPtr(_) |
ty::Ref(
_, /*rgn*/
_, /*ty*/
hir::MutImmutable
) => {
// don't continue traversing over derefs of raw pointers or shared
// borrows.
self.next = None;
return Some(cursor);
}
let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
match ty.sty {
ty::RawPtr(_) |
ty::Ref(
_, /*rgn*/
_, /*ty*/
hir::MutImmutable
) => {
// don't continue traversing over derefs of raw pointers or shared borrows.
self.next = None;
return Some(cursor);
ty::Ref(
_, /*rgn*/
_, /*ty*/
hir::MutMutable,
) => {
self.next = Some(PlaceRef {
base: cursor.base,
projection: proj_base,
});
return Some(cursor);
}
ty::Adt(..) if ty.is_box() => {
self.next = Some(PlaceRef {
base: cursor.base,
projection: proj_base,
});
return Some(cursor);
}
_ => panic!("unknown type fed to Projection Deref."),
}
}
ty::Ref(
_, /*rgn*/
_, /*ty*/
hir::MutMutable,
) => {
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}
ty::Adt(..) if ty.is_box() => {
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}
_ => panic!("unknown type fed to Projection Deref."),
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -282,53 +282,53 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
trace!("eval_place(place={:?})", place);
place.iterate(|place_base, place_projection| {
let mut eval = match place_base {
PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
let generics = self.tcx.generics_of(self.source.def_id());
if generics.requires_monomorphization(self.tcx) {
// FIXME: can't handle code with generics
return None;
}
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
let instance = Instance::new(self.source.def_id(), substs);
let cid = GlobalId {
instance,
promoted: Some(*promoted),
};
let res = self.use_ecx(source_info, |this| {
this.ecx.const_eval_raw(cid)
})?;
trace!("evaluated promoted {:?} to {:?}", promoted, res);
res.into()
}
_ => return None,
};
for proj in place_projection {
match proj.elem {
ProjectionElem::Field(field, _) => {
trace!("field proj on {:?}", proj.base);
eval = self.use_ecx(source_info, |this| {
this.ecx.operand_field(eval, field.index() as u64)
})?;
},
ProjectionElem::Deref => {
trace!("processing deref");
eval = self.use_ecx(source_info, |this| {
this.ecx.deref_operand(eval)
})?.into();
}
// We could get more projections by using e.g., `operand_projection`,
// but we do not even have the stack frame set up properly so
// an `Index` projection would throw us off-track.
_ => return None,
let mut eval = match place.base {
PlaceBase::Local(loc) => self.get_const(loc).clone()?,
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => {
let generics = self.tcx.generics_of(self.source.def_id());
if generics.requires_monomorphization(self.tcx) {
// FIXME: can't handle code with generics
return None;
}
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
let instance = Instance::new(self.source.def_id(), substs);
let cid = GlobalId {
instance,
promoted: Some(promoted),
};
let res = self.use_ecx(source_info, |this| {
this.ecx.const_eval_raw(cid)
})?;
trace!("evaluated promoted {:?} to {:?}", promoted, res);
res.into()
}
_ => return None,
};
Some(eval)
})
for (i, elem) in place.projection.iter().enumerate() {
let proj_base = &place.projection[..i];
match elem {
ProjectionElem::Field(field, _) => {
trace!("field proj on {:?}", proj_base);
eval = self.use_ecx(source_info, |this| {
this.ecx.operand_field(eval, field.index() as u64)
})?;
},
ProjectionElem::Deref => {
trace!("processing deref");
eval = self.use_ecx(source_info, |this| {
this.ecx.deref_operand(eval)
})?.into();
}
// We could get more projections by using e.g., `operand_projection`,
// but we do not even have the stack frame set up properly so
// an `Index` projection would throw us off-track.
_ => return None,
}
}
Some(eval)
}
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
@ -665,7 +665,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
location: Location,
) {
trace!("visit_statement: {:?}", statement);
if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
if let StatementKind::Assign(box(ref place, ref mut rval)) = statement.kind {
let place_ty: Ty<'tcx> = place
.ty(&self.local_decls, self.tcx)
.ty;
@ -673,7 +673,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
if let Place {
base: PlaceBase::Local(local),
projection: None,
projection: box [],
} = *place {
trace!("checking whether {:?} can be stored to {:?}", value, local);
if self.can_const_prop[local] {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -38,14 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
where
L: HasLocalDecls<'tcx>,
{
let mut place_projection = &place.projection;
for (i, elem) in place.projection.iter().enumerate().rev() {
let proj_base = &place.projection[..i];
while let Some(proj) = place_projection {
match proj.elem {
match elem {
// encountered a Deref, which is ABI-aligned
ProjectionElem::Deref => break,
ProjectionElem::Field(..) => {
let ty = Place::ty_from(&place.base, &proj.base, local_decls, tcx).ty;
let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
match ty.sty {
ty::Adt(def, _) if def.repr.packed() => {
return true
@ -55,7 +55,6 @@ where
}
_ => {}
}
place_projection = &proj.base;
}
false

View file

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

View file

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