Auto merge of #60913 - spastorino:place2_4, r=oli-obk

Place 2.0 change from enum to struct

r? @oli-obk
This commit is contained in:
bors 2019-07-21 03:25:05 +00:00
commit 1301422a6c
51 changed files with 1734 additions and 988 deletions

View file

@ -1718,11 +1718,11 @@ impl<'tcx> Debug for Statement<'tcx> {
#[derive(
Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)]
pub enum Place<'tcx> {
Base(PlaceBase<'tcx>),
pub struct Place<'tcx> {
pub base: PlaceBase<'tcx>,
/// projection out of a place (access a field, deref a pointer, etc)
Projection(Box<Projection<'tcx>>),
pub projection: Option<Box<Projection<'tcx>>>,
}
#[derive(
@ -1761,7 +1761,7 @@ impl_stable_hash_for!(struct Static<'tcx> {
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
)]
pub struct Projection<'tcx> {
pub base: Place<'tcx>,
pub base: Option<Box<Projection<'tcx>>>,
pub elem: PlaceElem<'tcx>,
}
@ -1826,8 +1826,17 @@ 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>>>,
}
impl<'tcx> Place<'tcx> {
pub const RETURN_PLACE: Place<'tcx> = Place::Base(PlaceBase::Local(RETURN_PLACE));
pub const RETURN_PLACE: Place<'tcx> = Place {
base: PlaceBase::Local(RETURN_PLACE),
projection: None,
};
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
self.elem(ProjectionElem::Field(f, ty))
@ -1853,7 +1862,10 @@ impl<'tcx> Place<'tcx> {
}
pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
Place::Projection(Box::new(Projection { base: self, elem }))
Place {
base: self.base,
projection: Some(Box::new(Projection { base: self.projection, elem })),
}
}
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
@ -1862,54 +1874,77 @@ impl<'tcx> Place<'tcx> {
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match self {
Place::Base(PlaceBase::Local(local))
| Place::Projection(box Projection {
base: Place::Base(PlaceBase::Local(local)),
elem: ProjectionElem::Deref,
}) => Some(*local),
Place {
base: PlaceBase::Local(local),
projection: None,
} |
Place {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
}),
} => Some(*local),
_ => None,
}
}
/// Finds the innermost `Local` from this `Place`.
pub fn base_local(&self) -> Option<Local> {
let mut place = self;
loop {
match place {
Place::Projection(proj) => place = &proj.base,
Place::Base(PlaceBase::Static(_)) => return None,
Place::Base(PlaceBase::Local(local)) => return Some(*local),
}
}
}
/// 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 {
self.iterate2(&Projections::Empty, op)
Place::iterate_over(&self.base, &self.projection, op)
}
fn iterate2<R>(
&self,
next: &Projections<'_, 'tcx>,
pub fn iterate_over<R>(
place_base: &PlaceBase<'tcx>,
place_projection: &Option<Box<Projection<'tcx>>>,
op: impl FnOnce(&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>) -> R,
) -> R {
match self {
Place::Projection(interior) => {
interior.base.iterate2(&Projections::List { projection: interior, next }, op)
}
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())
}
Place::Base(base) => op(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_place_ref(&self) -> PlaceRef<'_, 'tcx> {
PlaceRef {
base: &self.base,
projection: &self.projection,
}
}
}
impl From<Local> for Place<'_> {
fn from(local: Local) -> Self {
Place::Base(local.into())
Place {
base: local.into(),
projection: None,
}
}
}
@ -1919,6 +1954,36 @@ 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.
//
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match self {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} |
PlaceRef {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: 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`).
@ -3155,18 +3220,14 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
match self {
&Place::Projection(ref p) => Place::Projection(p.fold_with(folder)),
_ => self.clone(),
Place {
base: self.base.clone(),
projection: self.projection.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
if let &Place::Projection(ref p) = self {
p.visit_with(visitor)
} else {
false
}
self.projection.visit_with(visitor)
}
}

View file

@ -118,11 +118,15 @@ BraceStructTypeFoldableImpl! {
}
impl<'tcx> Place<'tcx> {
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
where
D: HasLocalDecls<'tcx>,
pub fn ty_from<D>(
base: &PlaceBase<'tcx>,
projection: &Option<Box<Projection<'tcx>>>,
local_decls: &D,
tcx: TyCtxt<'tcx>
) -> PlaceTy<'tcx>
where D: HasLocalDecls<'tcx>
{
self.iterate(|place_base, place_projections| {
Place::iterate_over(base, projection, |place_base, place_projections| {
let mut place_ty = place_base.ty(local_decls);
for proj in place_projections {
@ -132,6 +136,13 @@ impl<'tcx> Place<'tcx> {
place_ty
})
}
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
where
D: HasLocalDecls<'tcx>,
{
Place::ty_from(&self.base, &self.projection, local_decls, tcx)
}
}
impl<'tcx> PlaceBase<'tcx> {

View file

@ -159,10 +159,11 @@ macro_rules! make_mir_visitor {
}
fn visit_projection(&mut self,
place_base: & $($mutability)? PlaceBase<'tcx>,
place: & $($mutability)? Projection<'tcx>,
context: PlaceContext,
location: Location) {
self.super_projection(place, context, location);
self.super_projection(place_base, place, context, location);
}
fn visit_constant(&mut self,
@ -676,19 +677,20 @@ macro_rules! make_mir_visitor {
place: & $($mutability)? Place<'tcx>,
context: PlaceContext,
location: Location) {
match place {
Place::Base(place_base) => {
self.visit_place_base(place_base, context, location);
}
Place::Projection(proj) => {
let context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};
let mut context = context;
self.visit_projection(proj, context, location);
}
if place.projection.is_some() {
context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};
}
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);
}
}
@ -707,13 +709,14 @@ macro_rules! make_mir_visitor {
}
fn super_projection(&mut self,
place_base: & $($mutability)? PlaceBase<'tcx>,
proj: & $($mutability)? Projection<'tcx>,
context: PlaceContext,
location: Location) {
// this is calling `super_place` in preparation for changing `Place` to be
// a struct with a base and a slice of projections. `visit_place` should only ever
// be called for the outermost place now.
self.super_place(& $($mutability)? proj.base, context, location);
if let Some(box proj_base) = & $($mutability)? proj.base {
self.visit_projection(place_base, proj_base, context, location);
}
match & $($mutability)? proj.elem {
ProjectionElem::Deref => {
}

View file

@ -92,6 +92,86 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
self.first_assignment[local] = location;
}
}
fn process_place(&mut self,
place_ref: &mir::PlaceRef<'_, 'tcx>,
context: PlaceContext,
location: Location) {
let cx = self.fx.cx;
if let Some(proj) = place_ref.projection {
// Allow uses of projections that are ZSTs or from scalar fields.
let is_consume = match context {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
_ => false
};
if is_consume {
let base_ty =
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)
.ty;
let elem_ty = self.fx.monomorphize(&elem_ty);
if cx.layout_of(elem_ty).is_zst() {
return;
}
if let mir::ProjectionElem::Field(..) = proj.elem {
let layout = cx.layout_of(base_ty.ty);
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
// Recurse with the same context, instead of `Projection`,
// potentially stopping at non-operand projections,
// which would trigger `not_ssa` on locals.
self.process_place(
&mir::PlaceRef {
base: place_ref.base,
projection: &proj.base,
},
context,
location,
);
return;
}
}
}
// A deref projection only reads the pointer, never needs the place.
if let mir::ProjectionElem::Deref = proj.elem {
self.process_place(
&mir::PlaceRef {
base: place_ref.base,
projection: &proj.base,
},
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location
);
return;
}
}
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
// visit_place API
let mut context = context;
if place_ref.projection.is_some() {
context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};
}
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);
}
}
}
impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
@ -103,7 +183,10 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
location: Location) {
debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place {
if let mir::Place {
base: mir::PlaceBase::Local(index),
projection: None,
} = *place {
self.assign(index, location);
if !self.fx.rvalue_creates_operand(rvalue) {
self.not_ssa(index);
@ -155,51 +238,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
context: PlaceContext,
location: Location) {
debug!("visit_place(place={:?}, context={:?})", place, context);
let cx = self.fx.cx;
if let mir::Place::Projection(ref proj) = *place {
// Allow uses of projections that are ZSTs or from scalar fields.
let is_consume = match context {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
_ => false
};
if is_consume {
let base_ty = proj.base.ty(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)
.ty;
let elem_ty = self.fx.monomorphize(&elem_ty);
if cx.layout_of(elem_ty).is_zst() {
return;
}
if let mir::ProjectionElem::Field(..) = proj.elem {
let layout = cx.layout_of(base_ty.ty);
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
// Recurse with the same context, instead of `Projection`,
// potentially stopping at non-operand projections,
// which would trigger `not_ssa` on locals.
self.visit_place(&proj.base, context, location);
return;
}
}
}
// A deref projection only reads the pointer, never needs the place.
if let mir::ProjectionElem::Deref = proj.elem {
return self.visit_place(
&proj.base,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location
);
}
}
self.super_place(place, context, location);
self.process_place(&place.as_place_ref(), context, location);
}
fn visit_local(&mut self,

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);
self.codegen_consume(&mut bx, &mir::Place::RETURN_PLACE.as_place_ref());
if let Ref(llval, _, align) = op.val {
bx.load(llval, align)
} else {
@ -314,7 +314,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return
}
let place = self.codegen_place(&mut bx, location);
let place = self.codegen_place(&mut bx, &location.as_place_ref());
let (args1, args2);
let mut args = if let Some(llextra) = place.llextra {
args2 = [place.llval, llextra];
@ -607,18 +607,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// but specified directly in the code. This means it gets promoted
// and we can then extract the value by evaluating the promoted.
mir::Operand::Copy(
Place::Base(
PlaceBase::Static(
box Static { kind: StaticKind::Promoted(promoted), ty }
)
)
Place {
base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(promoted),
ty,
}),
projection: None,
}
) |
mir::Operand::Move(
Place::Base(
PlaceBase::Static(
box Static { kind: StaticKind::Promoted(promoted), ty }
)
)
Place {
base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(promoted),
ty,
}),
projection: None,
}
) => {
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
@ -1098,7 +1102,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if fn_ret.is_ignore() {
return ReturnDest::Nothing;
}
let dest = if let mir::Place::Base(mir::PlaceBase::Local(index)) = *dest {
let dest = if let mir::Place {
base: mir::PlaceBase::Local(index),
projection: None,
} = *dest {
match self.locals[index] {
LocalRef::Place(dest) => dest,
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
@ -1128,7 +1135,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
} else {
self.codegen_place(bx, dest)
self.codegen_place(bx, &mir::PlaceRef {
base: &dest.base,
projection: &dest.projection,
})
};
if fn_ret.is_indirect() {
if dest.align < dest.layout.align.abi {
@ -1153,12 +1163,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
src: &mir::Operand<'tcx>,
dst: &mir::Place<'tcx>
) {
if let mir::Place::Base(mir::PlaceBase::Local(index)) = *dst {
if let mir::Place {
base: mir::PlaceBase::Local(index),
projection: None,
} = *dst {
match self.locals[index] {
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
LocalRef::Operand(None) => {
let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst));
let dst_layout = bx.layout_of(self.monomorphized_place_ty(&dst.as_place_ref()));
assert!(!dst_layout.ty.has_erasable_regions());
let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
place.storage_live(bx);
@ -1173,7 +1186,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
} else {
let dst = self.codegen_place(bx, dst);
let dst = self.codegen_place(bx, &dst.as_place_ref());
self.codegen_transmute_into(bx, src, dst);
}
}

View file

@ -380,11 +380,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn maybe_codegen_consume_direct(
&mut self,
bx: &mut Bx,
place: &mir::Place<'tcx>
place_ref: &mir::PlaceRef<'_, 'tcx>
) -> Option<OperandRef<'tcx, Bx::Value>> {
debug!("maybe_codegen_consume_direct(place={:?})", place);
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
place.iterate(|place_base, place_projection| {
place_ref.iterate(|place_base, place_projection| {
if let mir::PlaceBase::Local(index) = place_base {
match self.locals[*index] {
LocalRef::Operand(Some(mut o)) => {
@ -413,7 +413,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some(o)
}
LocalRef::Operand(None) => {
bug!("use of {:?} before def", place);
bug!("use of {:?} before def", place_ref);
}
LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
// watch out for locals that do not have an
@ -430,11 +430,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn codegen_consume(
&mut self,
bx: &mut Bx,
place: &mir::Place<'tcx>
place_ref: &mir::PlaceRef<'_, 'tcx>
) -> OperandRef<'tcx, Bx::Value> {
debug!("codegen_consume(place={:?})", place);
debug!("codegen_consume(place_ref={:?})", place_ref);
let ty = self.monomorphized_place_ty(place);
let ty = self.monomorphized_place_ty(place_ref);
let layout = bx.cx().layout_of(ty);
// ZSTs don't require any actual memory access.
@ -442,13 +442,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return OperandRef::new_zst(bx, layout);
}
if let Some(o) = self.maybe_codegen_consume_direct(bx, place) {
if let Some(o) = self.maybe_codegen_consume_direct(bx, place_ref) {
return o;
}
// for most places, to consume them we just load them
// out from their home
let place = self.codegen_place(bx, place);
let place = self.codegen_place(bx, place_ref);
bx.load_operand(place)
}
@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
match *operand {
mir::Operand::Copy(ref place) |
mir::Operand::Move(ref place) => {
self.codegen_consume(bx, place)
self.codegen_consume(bx, &place.as_place_ref())
}
mir::Operand::Constant(ref constant) => {

View file

@ -428,16 +428,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn codegen_place(
&mut self,
bx: &mut Bx,
place: &mir::Place<'tcx>
place_ref: &mir::PlaceRef<'_, 'tcx>
) -> PlaceRef<'tcx, Bx::Value> {
debug!("codegen_place(place={:?})", place);
debug!("codegen_place(place_ref={:?})", place_ref);
let cx = self.cx;
let tcx = self.cx.tcx();
let result = match *place {
mir::Place::Base(mir::PlaceBase::Local(index)) => {
match self.locals[index] {
let result = match &place_ref {
mir::PlaceRef {
base: mir::PlaceBase::Local(index),
projection: None,
} => {
match self.locals[*index] {
LocalRef::Place(place) => {
return place;
}
@ -445,19 +447,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return bx.load_operand(place).deref(cx);
}
LocalRef::Operand(..) => {
bug!("using operand local {:?} as place", place);
bug!("using operand local {:?} as place", place_ref);
}
}
}
mir::Place::Base(
mir::PlaceBase::Static(
box mir::Static { ty, kind: mir::StaticKind::Promoted(promoted) }
)
) => {
mir::PlaceRef {
base: mir::PlaceBase::Static(box mir::Static {
ty,
kind: mir::StaticKind::Promoted(promoted),
}),
projection: None,
} => {
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
instance: self.instance,
promoted: Some(promoted),
promoted: Some(*promoted),
};
let layout = cx.layout_of(self.monomorphize(&ty));
match bx.tcx().const_eval(param_env.and(cid)) {
@ -480,26 +484,41 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
}
mir::Place::Base(
mir::PlaceBase::Static(
box mir::Static { ty, kind: mir::StaticKind::Static(def_id) }
)
) => {
mir::PlaceRef {
base: mir::PlaceBase::Static(box mir::Static {
ty,
kind: mir::StaticKind::Static(def_id),
}),
projection: None,
} => {
// NB: The layout of a static may be unsized as is the case when working
// with a static that is an extern_type.
let layout = cx.layout_of(self.monomorphize(&ty));
let static_ = bx.get_static(def_id);
let static_ = bx.get_static(*def_id);
PlaceRef::new_thin_place(bx, static_, layout, layout.align.abi)
},
mir::Place::Projection(box mir::Projection {
ref base,
elem: mir::ProjectionElem::Deref
}) => {
mir::PlaceRef {
base,
projection: Some(box mir::Projection {
base: proj_base,
elem: mir::ProjectionElem::Deref,
}),
} => {
// Load the pointer from its location.
self.codegen_consume(bx, base).deref(bx.cx())
self.codegen_consume(bx, &mir::PlaceRef {
base,
projection: proj_base,
}).deref(bx.cx())
}
mir::Place::Projection(ref projection) => {
let cg_base = self.codegen_place(bx, &projection.base);
mir::PlaceRef {
base,
projection: Some(projection),
} => {
// FIXME turn this recursion into iteration
let cg_base = self.codegen_place(bx, &mir::PlaceRef {
base,
projection: &projection.base,
});
match projection.elem {
mir::ProjectionElem::Deref => bug!(),
@ -553,13 +572,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
};
debug!("codegen_place(place={:?}) => {:?}", place, result);
debug!("codegen_place(place={:?}) => {:?}", place_ref, result);
result
}
pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> {
pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> {
let tcx = self.cx.tcx();
let place_ty = place.ty(self.mir, tcx);
let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, self.mir, tcx);
self.monomorphize(&place_ty.ty)
}
}

View file

@ -355,7 +355,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
mir::Rvalue::Ref(_, bk, ref place) => {
let cg_place = self.codegen_place(&mut bx, place);
let cg_place = self.codegen_place(&mut bx, &place.as_place_ref());
let ty = cg_place.layout.ty;
@ -446,7 +446,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::Rvalue::Discriminant(ref place) => {
let discr_ty = rvalue.ty(&*self.mir, bx.tcx());
let discr = self.codegen_place(&mut bx, place)
let discr = self.codegen_place(&mut bx, &place.as_place_ref())
.codegen_get_discr(&mut bx, discr_ty);
(bx, OperandRef {
val: OperandValue::Immediate(discr),
@ -515,7 +515,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> Bx::Value {
// ZST are passed as operands and require special handling
// because codegen_place() panics if Local is operand.
if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place {
if let mir::Place {
base: mir::PlaceBase::Local(index),
projection: None,
} = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::Array(_, n) = op.layout.ty.sty {
let n = n.unwrap_usize(bx.cx().tcx());
@ -524,8 +527,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
// use common size calculation for non zero-sized types
let cg_value = self.codegen_place(bx, place);
return cg_value.len(bx.cx());
let cg_value = self.codegen_place(bx, &place.as_place_ref());
cg_value.len(bx.cx())
}
pub fn codegen_scalar_binop(

View file

@ -17,7 +17,10 @@ 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) => {
if let mir::Place::Base(mir::PlaceBase::Local(index)) = *place {
if let mir::Place {
base: mir::PlaceBase::Local(index),
projection: None,
} = *place {
match self.locals[index] {
LocalRef::Place(cg_dest) => {
self.codegen_rvalue(bx, cg_dest, rvalue)
@ -43,12 +46,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
} else {
let cg_dest = self.codegen_place(&mut bx, place);
let cg_dest = self.codegen_place(&mut bx, &place.as_place_ref());
self.codegen_rvalue(bx, cg_dest, rvalue)
}
}
mir::StatementKind::SetDiscriminant{ref place, variant_index} => {
self.codegen_place(&mut bx, place)
self.codegen_place(&mut bx, &place.as_place_ref())
.codegen_set_discr(&mut bx, variant_index);
bx
}
@ -70,7 +73,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
mir::StatementKind::InlineAsm(ref asm) => {
let outputs = asm.outputs.iter().map(|output| {
self.codegen_place(&mut bx, output)
self.codegen_place(&mut bx, &output.as_place_ref())
}).collect();
let input_vals = asm.inputs.iter()

View file

@ -209,7 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);
if let Some(local) = borrowed_place.base_local() {
if let mir::PlaceBase::Local(local) = borrowed_place.base {
self.local_map.entry(local).or_default().insert(idx);
}
}
@ -315,7 +315,10 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
// TEMP = &foo
//
// so extract `temp`.
let temp = if let &mir::Place::Base(mir::PlaceBase::Local(temp)) = assigned_place {
let temp = if let &mir::Place {
base: mir::PlaceBase::Local(temp),
projection: None,
} = assigned_place {
temp
} else {
span_bug!(

View file

@ -2,7 +2,7 @@ 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,
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
};
use rustc::ty::{self, Ty};
@ -48,7 +48,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self,
location: Location,
desired_action: InitializationRequiringAction,
(moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
(moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span),
mpi: MovePathIndex,
) {
debug!(
@ -72,9 +72,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.collect();
if move_out_indices.is_empty() {
let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
let root_place = self
.prefixes(used_place, PrefixSet::All)
.last()
.unwrap();
if self.uninitialized_error_reported.contains(root_place) {
if self.uninitialized_error_reported.contains(&root_place) {
debug!(
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
root_place
@ -82,7 +85,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return;
}
self.uninitialized_error_reported.insert(root_place.clone());
self.uninitialized_error_reported.insert(root_place);
let item_msg = match self.describe_place_with_options(used_place,
IncludingDowncast(true)) {
@ -105,7 +108,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.buffer(&mut self.errors_buffer);
} else {
if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
if self.prefixes(&reported_place, PrefixSet::All)
if self.prefixes(*reported_place, PrefixSet::All)
.any(|p| p == used_place)
{
debug!(
@ -123,7 +126,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
desired_action.as_noun(),
msg,
self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
self.describe_place_with_options(moved_place, IncludingDowncast(true)),
);
self.add_moved_or_invoked_closure_note(
@ -136,13 +139,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let is_partial_move = move_site_vec.iter().any(|move_site| {
let move_out = self.move_data.moves[(*move_site).moi];
let moved_place = &self.move_data.move_paths[move_out.path].place;
used_place != moved_place && used_place.is_prefix_of(moved_place)
used_place != moved_place.as_place_ref()
&& used_place.is_prefix_of(moved_place.as_place_ref())
});
for move_site in &move_site_vec {
let move_out = self.move_data.moves[(*move_site).moi];
let moved_place = &self.move_data.move_paths[move_out.path].place;
let move_spans = self.move_spans(moved_place, move_out.source);
let move_spans = self.move_spans(moved_place.as_place_ref(), move_out.source);
let move_span = move_spans.args_or_use();
let move_msg = if move_spans.for_closure() {
@ -200,7 +204,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
let ty =
Place::ty_from(used_place.base, used_place.projection, self.body, self.infcx.tcx)
.ty;
let needs_note = match ty.sty {
ty::Closure(id, _) => {
let tables = self.infcx.tcx.typeck_tables_of(id);
@ -216,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let place = &self.move_data.move_paths[mpi].place;
let ty = place.ty(self.body, self.infcx.tcx).ty;
let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
let opt_name =
self.describe_place_with_options(place.as_place_ref(), IncludingDowncast(true));
let note_msg = match opt_name {
Some(ref name) => format!("`{}`", name),
None => "value".to_owned(),
@ -232,7 +239,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
}
let span = if let Place::Base(PlaceBase::Local(local)) = place {
let span = if let Place {
base: PlaceBase::Local(local),
projection: None,
} = place {
let decl = &self.body.local_decls[*local];
Some(decl.source_info.span)
} else {
@ -247,7 +257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
if let Some((_, mut old_err)) = self.move_error_reported
.insert(move_out_indices, (used_place.clone(), err))
.insert(move_out_indices, (used_place, err))
{
// Cancel the old error so it doesn't ICE.
old_err.cancel();
@ -265,11 +275,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
location, place, span, borrow
);
let value_msg = match self.describe_place(place) {
let value_msg = match self.describe_place(place.as_place_ref()) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
let borrow_msg = match self.describe_place(borrow.borrowed_place.as_place_ref()) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
@ -277,12 +287,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.args_or_use();
let move_spans = self.move_spans(place, location);
let move_spans = self.move_spans(place.as_place_ref(), location);
let span = move_spans.args_or_use();
let mut err = self.cannot_move_when_borrowed(
span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
&self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
);
err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
err.span_label(span, format!("move out of {} occurs here", value_msg));
@ -316,20 +326,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Conflicting borrows are reported separately, so only check for move
// captures.
let use_spans = self.move_spans(place, location);
let use_spans = self.move_spans(place.as_place_ref(), location);
let span = use_spans.var_or_use();
let mut err = self.cannot_use_when_mutably_borrowed(
span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
&self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
borrow_span,
&self.describe_place(&borrow.borrowed_place)
&self.describe_place(borrow.borrowed_place.as_place_ref())
.unwrap_or_else(|| "_".to_owned()),
);
borrow_spans.var_span_label(&mut err, {
let place = &borrow.borrowed_place;
let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
let desc_place =
self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned());
format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
});
@ -506,7 +517,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
} else {
let borrow_place = &issued_borrow.borrowed_place;
let borrow_place_desc = self.describe_place(borrow_place)
let borrow_place_desc = self.describe_place(borrow_place.as_place_ref())
.unwrap_or_else(|| "_".to_owned());
issued_spans.var_span_label(
&mut err,
@ -575,8 +586,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> (String, String, String, String) {
// Define a small closure that we can use to check if the type of a place
// is a union.
let union_ty = |place: &Place<'tcx>| -> Option<Ty<'tcx>> {
let ty = place.ty(self.body, self.infcx.tcx).ty;
let union_ty = |place_base, place_projection| {
let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty;
ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
};
let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned());
@ -595,13 +606,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// field access to a union. If we find that, then we will keep the place of the
// union being accessed and the field that was being accessed so we can check the
// second borrowed place for the same union and a access to a different field.
let mut current = first_borrowed_place;
while let Place::Projection(box Projection { base, elem }) = current {
let Place {
base,
projection,
} = first_borrowed_place;
let mut current = projection;
while let Some(box Projection { base: base_proj, elem }) = current {
match elem {
ProjectionElem::Field(field, _) if union_ty(base).is_some() => {
return Some((base, field));
ProjectionElem::Field(field, _) if union_ty(base, base_proj).is_some() => {
return Some((PlaceRef {
base: base,
projection: base_proj,
}, field));
},
_ => current = base,
_ => current = base_proj,
}
}
None
@ -609,22 +629,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.and_then(|(target_base, target_field)| {
// With the place of a union and a field access into it, we traverse the second
// borrowed place and look for a access to a different field of the same union.
let mut current = second_borrowed_place;
while let Place::Projection(box Projection { base, elem }) = current {
let Place {
base,
projection,
} = second_borrowed_place;
let mut current = projection;
while let Some(box Projection { base: proj_base, elem }) = current {
if let ProjectionElem::Field(field, _) = elem {
if let Some(union_ty) = union_ty(base) {
if field != target_field && base == target_base {
if let Some(union_ty) = union_ty(base, proj_base) {
if field != target_field
&& base == target_base.base
&& proj_base == target_base.projection {
// FIXME when we avoid clone reuse describe_place closure
let describe_base_place = self.describe_place(PlaceRef {
base: base,
projection: proj_base,
}).unwrap_or_else(|| "_".to_owned());
return Some((
describe_place(base),
describe_place(first_borrowed_place),
describe_place(second_borrowed_place),
describe_base_place,
describe_place(first_borrowed_place.as_place_ref()),
describe_place(second_borrowed_place.as_place_ref()),
union_ty.to_string(),
));
}
}
}
current = base;
current = proj_base;
}
None
})
@ -632,7 +666,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If we didn't find a field access into a union, or both places match, then
// only return the description of the first place.
(
describe_place(first_borrowed_place),
describe_place(first_borrowed_place.as_place_ref()),
"".to_string(),
"".to_string(),
"".to_string(),
@ -663,20 +697,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
let drop_span = place_span.1;
let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(), PrefixSet::All)
.last()
.unwrap();
let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.var_or_use();
let proper_span = match *root_place {
Place::Base(PlaceBase::Local(local)) => self.body.local_decls[local].source_info.span,
assert!(root_place.projection.is_none());
let proper_span = match root_place.base {
PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
_ => drop_span,
};
if self.access_place_error_reported
.contains(&(root_place.clone(), borrow_span))
.contains(&(Place {
base: root_place.base.clone(),
projection: root_place.projection.clone(),
}, borrow_span))
{
debug!(
"suppressing access_place error when borrow doesn't live long enough for {:?}",
@ -686,16 +724,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
self.access_place_error_reported
.insert((root_place.clone(), borrow_span));
.insert((Place {
base: root_place.base.clone(),
projection: root_place.projection.clone(),
}, borrow_span));
if let StorageDeadOrDrop::Destructor(dropped_ty) =
self.classify_drop_access_kind(&borrow.borrowed_place)
self.classify_drop_access_kind(borrow.borrowed_place.as_place_ref())
{
// If a borrow of path `B` conflicts with drop of `D` (and
// we're not in the uninteresting case where `B` is a
// prefix of `D`), then report this as a more interesting
// destructor conflict.
if !borrow.borrowed_place.is_prefix_of(place_span.0) {
if !borrow.borrowed_place.as_place_ref().is_prefix_of(place_span.0.as_place_ref()) {
self.report_borrow_conflicts_with_destructor(
location, borrow, place_span, kind, dropped_ty,
);
@ -703,7 +744,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
let place_desc = self.describe_place(&borrow.borrowed_place);
let place_desc = self.describe_place(borrow.borrowed_place.as_place_ref());
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
@ -910,12 +951,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut err = self.cannot_borrow_across_destructor(borrow_span);
let what_was_dropped = match self.describe_place(place) {
let what_was_dropped = match self.describe_place(place.as_place_ref()) {
Some(name) => format!("`{}`", name.as_str()),
None => String::from("temporary value"),
};
let label = match self.describe_place(&borrow.borrowed_place) {
let label = match self.describe_place(borrow.borrowed_place.as_place_ref()) {
Some(borrowed) => format!(
"here, drop of {D} needs exclusive access to `{B}`, \
because the type `{T}` implements the `Drop` trait",
@ -1061,7 +1102,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
let local_kind = match borrow.borrowed_place {
Place::Base(PlaceBase::Local(local)) => {
Place {
base: PlaceBase::Local(local),
projection: None,
} => {
match self.body.local_kind(local) {
LocalKind::ReturnPointer
| LocalKind::Temp => bug!("temporary or return pointer with a name"),
@ -1083,15 +1127,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
format!("`{}` is borrowed here", place_desc),
)
} else {
let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(),
PrefixSet::All)
.last()
.unwrap();
let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
let local = if let PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} = root_place {
local
} else {
bug!("try_report_cannot_return_reference_to_local: not a local")
};
match self.body.local_kind(local) {
match self.body.local_kind(*local) {
LocalKind::ReturnPointer | LocalKind::Temp => {
(
"temporary value".to_string(),
@ -1342,7 +1390,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut err = self.cannot_mutate_in_match_guard(
span,
loan_span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
&self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
"assign",
);
loan_spans.var_span_label(
@ -1358,7 +1406,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut err = self.cannot_assign_to_borrowed(
span,
loan_span,
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
&self.describe_place(place.as_place_ref()).unwrap_or_else(|| "_".to_owned()),
);
loan_spans.var_span_label(
@ -1385,7 +1433,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assigned_span: Span,
err_place: &Place<'tcx>,
) {
let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place {
let (from_arg, local_decl) = if let Place {
base: PlaceBase::Local(local),
projection: None,
} = *err_place {
if let LocalKind::Arg = self.body.local_kind(local) {
(true, Some(&self.body.local_decls[local]))
} else {
@ -1415,8 +1466,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
is_user_variable: None,
..
})
| None => (self.describe_place(place), assigned_span),
Some(decl) => (self.describe_place(err_place), decl.source_info.span),
| None => (self.describe_place(place.as_place_ref()), assigned_span),
Some(decl) => (self.describe_place(err_place.as_place_ref()), decl.source_info.span),
};
let mut err = self.cannot_reassign_immutable(
@ -1454,21 +1505,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.buffer(&mut self.errors_buffer);
}
fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> {
let tcx = self.infcx.tcx;
match place {
Place::Base(PlaceBase::Local(_)) |
Place::Base(PlaceBase::Static(_)) => {
match place.projection {
None => {
StorageDeadOrDrop::LocalStorageDead
}
Place::Projection(box Projection { base, elem }) => {
let base_access = self.classify_drop_access_kind(base);
Some(box Projection { ref base, ref elem }) => {
let base_access = self.classify_drop_access_kind(PlaceRef {
base: place.base,
projection: base,
});
match elem {
ProjectionElem::Deref => match base_access {
StorageDeadOrDrop::LocalStorageDead
| StorageDeadOrDrop::BoxedStorageDead => {
assert!(
base.ty(self.body, tcx).ty.is_box(),
Place::ty_from(&place.base, base, self.body, tcx).ty.is_box(),
"Drop of value behind a reference or raw pointer"
);
StorageDeadOrDrop::BoxedStorageDead
@ -1476,7 +1529,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
StorageDeadOrDrop::Destructor(_) => base_access,
},
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
let base_ty = base.ty(self.body, tcx).ty;
let base_ty = Place::ty_from(&place.base, base, self.body, tcx).ty;
match base_ty.sty {
ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor
@ -1543,8 +1596,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
// Check that the initial assignment of the reserve location is into a temporary.
let mut target = *match reservation {
Place::Base(PlaceBase::Local(local))
if self.body.local_kind(*local) == LocalKind::Temp => local,
Place {
base: PlaceBase::Local(local),
projection: None,
} if self.body.local_kind(*local) == LocalKind::Temp => local,
_ => return None,
};
@ -1557,7 +1612,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
target, stmt
);
if let StatementKind::Assign(
Place::Base(PlaceBase::Local(assigned_to)),
Place {
base: PlaceBase::Local(assigned_to),
projection: None,
},
box rvalue
) = &stmt.kind {
debug!(
@ -1682,7 +1740,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
target, terminator
);
if let TerminatorKind::Call {
destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)),
destination: Some((Place {
base: PlaceBase::Local(assigned_to),
projection: None,
}, _)),
args,
..
} = &terminator.kind

View file

@ -3,8 +3,8 @@ use rustc::hir::def::Namespace;
use rustc::hir::def_id::DefId;
use rustc::mir::{
AggregateKind, Constant, Field, Local, LocalKind, Location, Operand,
Place, PlaceBase, ProjectionElem, Rvalue, Statement, StatementKind, Static,
StaticKind, Terminator, TerminatorKind,
Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
Static, StaticKind, Terminator, TerminatorKind,
};
use rustc::ty::{self, DefIdTree, Ty, TyCtxt};
use rustc::ty::layout::VariantIdx;
@ -34,7 +34,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
pub(super) fn add_moved_or_invoked_closure_note(
&self,
location: Location,
place: &Place<'tcx>,
place: PlaceRef<'cx, 'tcx>,
diag: &mut DiagnosticBuilder<'_>,
) {
debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
@ -121,8 +121,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// End-user visible description of `place` if one can be found. If the
/// place is a temporary for instance, None will be returned.
pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
self.describe_place_with_options(place, IncludingDowncast(false))
pub(super) fn describe_place(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option<String> {
self.describe_place_with_options(place_ref, IncludingDowncast(false))
}
/// End-user visible description of `place` if one can be found. If the
@ -131,7 +131,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// `Downcast` and `IncludingDowncast` is true
pub(super) fn describe_place_with_options(
&self,
place: &Place<'tcx>,
place: PlaceRef<'cx, 'tcx>,
including_downcast: IncludingDowncast,
) -> Option<String> {
let mut buf = String::new();
@ -144,22 +144,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Appends end-user visible description of `place` to `buf`.
fn append_place_to_string(
&self,
place: &Place<'tcx>,
place: PlaceRef<'cx, 'tcx>,
buf: &mut String,
mut autoderef: bool,
including_downcast: &IncludingDowncast,
) -> Result<(), ()> {
match *place {
Place::Base(PlaceBase::Local(local)) => {
self.append_local_to_string(local, buf)?;
match place {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} => {
self.append_local_to_string(*local, buf)?;
}
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
PlaceRef {
base:
PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}),
projection: None,
} => {
buf.push_str("promoted");
}
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
buf.push_str(&self.infcx.tcx.item_name(def_id).to_string());
PlaceRef {
base:
PlaceBase::Static(box Static {
kind: StaticKind::Static(def_id),
..
}),
projection: None,
} => {
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
}
Place::Projection(ref proj) => {
PlaceRef {
ref base,
projection: Some(ref proj),
} => {
match proj.elem {
ProjectionElem::Deref => {
let upvar_field_projection =
@ -174,43 +194,66 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
} else {
if autoderef {
// FIXME turn this recursion into iteration
self.append_place_to_string(
&proj.base,
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
)?;
} else if let Place::Base(PlaceBase::Local(local)) = proj.base {
if self.body.local_decls[local].is_ref_for_guard() {
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
} else {
buf.push_str(&"*");
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
}
} else {
buf.push_str(&"*");
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
match (&proj.base, base) {
(None, PlaceBase::Local(local)) => {
if self.body.local_decls[*local].is_ref_for_guard() {
self.append_place_to_string(
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
)?;
} else {
// FIXME deduplicate this and the _ => body below
buf.push_str(&"*");
self.append_place_to_string(
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
)?;
}
}
_ => {
buf.push_str(&"*");
self.append_place_to_string(
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
)?;
}
}
}
}
}
ProjectionElem::Downcast(..) => {
self.append_place_to_string(
&proj.base,
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
@ -229,9 +272,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let name = self.upvars[var_index].name.to_string();
buf.push_str(&name);
} else {
let field_name = self.describe_field(&proj.base, field);
let field_name = self.describe_field(PlaceRef {
base: base,
projection: &proj.base,
}, field);
self.append_place_to_string(
&proj.base,
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
@ -243,7 +292,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
autoderef = true;
self.append_place_to_string(
&proj.base,
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
@ -260,7 +312,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// then use another while the borrow is held, don't output indices details
// to avoid confusing the end-user
self.append_place_to_string(
&proj.base,
PlaceRef {
base: &base,
projection: &proj.base,
},
buf,
autoderef,
&including_downcast,
@ -288,18 +343,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
/// End-user visible description of the `field`nth field of `base`
fn describe_field(&self, base: &Place<'tcx>, field: Field) -> String {
match *base {
Place::Base(PlaceBase::Local(local)) => {
let local = &self.body.local_decls[local];
fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
// FIXME Place2 Make this work iteratively
match place {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} => {
let local = &self.body.local_decls[*local];
self.describe_field_from_ty(&local.ty, field, None)
}
Place::Base(PlaceBase::Static(ref static_)) =>
PlaceRef {
base: PlaceBase::Static(static_),
projection: None,
} =>
self.describe_field_from_ty(&static_.ty, field, None),
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Deref => self.describe_field(&proj.base, field),
PlaceRef {
base,
projection: Some(proj),
} => match proj.elem {
ProjectionElem::Deref => self.describe_field(PlaceRef {
base,
projection: &proj.base,
}, field),
ProjectionElem::Downcast(_, variant_index) => {
let base_ty = base.ty(self.body, self.infcx.tcx).ty;
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))
}
ProjectionElem::Field(_, field_type) => {
@ -308,7 +377,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
self.describe_field(&proj.base, field)
self.describe_field(PlaceRef {
base,
projection: &proj.base,
}, field)
}
},
}
@ -365,10 +437,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
/// Checks if a place is a thread-local static.
pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
if let Place::Base(
PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })
) = place {
pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool {
if let PlaceRef {
base: PlaceBase::Static(box Static {
kind: StaticKind::Static(def_id),
..
}),
projection: None,
} = 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));
@ -405,7 +481,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
pub(super) fn borrowed_content_source(
&self,
deref_base: &Place<'tcx>,
deref_base: PlaceRef<'cx, 'tcx>,
) -> BorrowedContentSource<'tcx> {
let tcx = self.infcx.tcx;
@ -457,7 +533,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If we didn't find an overloaded deref or index, then assume it's a
// built in deref and check the type of the base.
let base_ty = deref_base.ty(self.body, tcx).ty;
let base_ty = Place::ty_from(deref_base.base, deref_base.projection, self.body, tcx).ty;
if base_ty.is_unsafe_ptr() {
BorrowedContentSource::DerefRawPointer
} else if base_ty.is_mutable_pointer() {
@ -700,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Finds the spans associated to a move or copy of move_place at location.
pub(super) fn move_spans(
&self,
moved_place: &Place<'tcx>, // Could also be an upvar.
moved_place: PlaceRef<'cx, 'tcx>, // Could also be an upvar.
location: Location,
) -> UseSpans {
use self::UseSpans::*;
@ -750,7 +826,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.get(location.statement_index)
{
Some(&Statement {
kind: StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _),
kind: StatementKind::Assign(Place {
base: PlaceBase::Local(local),
projection: None,
}, _),
..
}) => local,
_ => return OtherUse(use_span),
@ -776,7 +855,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id, is_generator, places
);
if let Some((args_span, var_span)) = self.closure_span(
*def_id, &Place::from(target), places
*def_id, Place::from(target).as_place_ref(), places
) {
return ClosureUse {
is_generator,
@ -800,7 +879,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn closure_span(
&self,
def_id: DefId,
target_place: &Place<'tcx>,
target_place: PlaceRef<'cx, 'tcx>,
places: &Vec<Operand<'tcx>>,
) -> Option<(Span, Span)> {
debug!(
@ -816,7 +895,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
match place {
Operand::Copy(place) |
Operand::Move(place) if target_place == place => {
Operand::Move(place) if target_place == place.as_place_ref() => {
debug!("closure_span: found captured local {:?}", place);
return Some((*args_span, upvar.span));
},

View file

@ -10,9 +10,8 @@ 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, Static,
StaticKind
ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef,
Static, StaticKind
};
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
@ -474,10 +473,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
/// when errors in the map are being re-added to the error buffer so that errors with the
/// same primary span come out in a consistent order.
move_error_reported: BTreeMap<Vec<MoveOutIndex>, (Place<'tcx>, DiagnosticBuilder<'cx>)>,
move_error_reported: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'cx, 'tcx>, DiagnosticBuilder<'cx>)>,
/// This field keeps track of errors reported in the checking of uninitialized variables,
/// so that we don't report seemingly duplicate errors.
uninitialized_error_reported: FxHashSet<Place<'tcx>>,
uninitialized_error_reported: FxHashSet<PlaceRef<'cx, 'tcx>>,
/// Errors to be reported buffer
errors_buffer: Vec<Diagnostic>,
/// This field keeps track of all the local variables that are declared mut and are mutated.
@ -520,7 +519,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
fn visit_statement_entry(
&mut self,
location: Location,
stmt: &Statement<'tcx>,
stmt: &'cx Statement<'tcx>,
flow_state: &Self::FlowState,
) {
debug!(
@ -561,7 +560,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
(place, span),
(place.as_place_ref(), span),
flow_state,
);
}
@ -592,7 +591,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
(output, o.span),
(output.as_place_ref(), o.span),
flow_state,
);
} else {
@ -631,7 +630,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
fn visit_terminator_entry(
&mut self,
location: Location,
term: &Terminator<'tcx>,
term: &'cx Terminator<'tcx>,
flow_state: &Self::FlowState,
) {
let loc = location;
@ -890,7 +889,8 @@ enum InitializationRequiringAction {
}
struct RootPlace<'d, 'tcx> {
place: &'d Place<'tcx>,
place_base: &'d PlaceBase<'tcx>,
place_projection: &'d Option<Box<Projection<'tcx>>>,
is_local_mutation_allowed: LocalMutationIsAllowed,
}
@ -1143,7 +1143,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn mutate_place(
&mut self,
location: Location,
place_span: (&Place<'tcx>, Span),
place_span: (&'cx Place<'tcx>, Span),
kind: AccessDepth,
mode: MutateMode,
flow_state: &Flows<'cx, 'tcx>,
@ -1154,7 +1154,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Update,
place_span,
(place_span.0.as_place_ref(), place_span.1),
flow_state,
);
}
@ -1166,12 +1166,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Special case: you can assign a immutable local variable
// (e.g., `x = ...`) so long as it has never been initialized
// before (at this point in the flow).
if let &Place::Base(PlaceBase::Local(local)) = place_span.0 {
if let Mutability::Not = self.body.local_decls[local].mutability {
if let Place {
base: PlaceBase::Local(local),
projection: None,
} = place_span.0 {
if let Mutability::Not = self.body.local_decls[*local].mutability {
// check for reassignments to immutable local variables
self.check_if_reassignment_to_immutable_state(
location,
local,
*local,
place_span,
flow_state,
);
@ -1192,7 +1195,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn consume_rvalue(
&mut self,
location: Location,
(rvalue, span): (&Rvalue<'tcx>, Span),
(rvalue, span): (&'cx Rvalue<'tcx>, Span),
flow_state: &Flows<'cx, 'tcx>,
) {
match *rvalue {
@ -1229,7 +1232,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.check_if_path_or_subpath_is_moved(
location,
action,
(place, span),
(place.as_place_ref(), span),
flow_state,
);
}
@ -1257,7 +1260,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
(place, span),
(place.as_place_ref(), span),
flow_state,
);
}
@ -1305,16 +1308,12 @@ 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>| {
match *place {
Place::Projection { .. } => {
if let Some(field) = this.is_upvar_field_projection(place) {
this.used_mut_upvars.push(field);
}
if place.projection.is_some() {
if let Some(field) = this.is_upvar_field_projection(place.as_place_ref()) {
this.used_mut_upvars.push(field);
}
Place::Base(PlaceBase::Local(local)) => {
this.used_mut.insert(local);
}
Place::Base(PlaceBase::Static(_)) => {}
} else if let PlaceBase::Local(local) = place.base {
this.used_mut.insert(local);
}
};
@ -1322,10 +1321,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// captures of a closure are copied/moved directly
// when generating MIR.
match *operand {
Operand::Move(Place::Base(PlaceBase::Local(local)))
| Operand::Copy(Place::Base(PlaceBase::Local(local)))
if self.body.local_decls[local].is_user_variable.is_none() =>
{
Operand::Move(Place {
base: PlaceBase::Local(local),
projection: None,
}) |
Operand::Copy(Place {
base: PlaceBase::Local(local),
projection: None,
}) if self.body.local_decls[local].is_user_variable.is_none() => {
if self.body.local_decls[local].ty.is_mutable_pointer() {
// The variable will be marked as mutable by the borrow.
return;
@ -1379,7 +1382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn consume_operand(
&mut self,
location: Location,
(operand, span): (&Operand<'tcx>, Span),
(operand, span): (&'cx Operand<'tcx>, Span),
flow_state: &Flows<'cx, 'tcx>,
) {
match *operand {
@ -1398,7 +1401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
(place, span),
(place.as_place_ref(), span),
flow_state,
);
}
@ -1416,7 +1419,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.check_if_path_or_subpath_is_moved(
location,
InitializationRequiringAction::Use,
(place, span),
(place.as_place_ref(), span),
flow_state,
);
}
@ -1434,30 +1437,35 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) {
debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = &borrow.borrowed_place;
let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
let root_place = self.prefixes(place.as_place_ref(), PrefixSet::All).last().unwrap();
// FIXME(nll-rfc#40): do more precise destructor tracking here. For now
// we just know that all locals are dropped at function exit (otherwise
// we'll have a memory leak) and assume that all statics have a destructor.
//
// FIXME: allow thread-locals to borrow other thread locals?
let (might_be_alive, will_be_dropped) = match root_place {
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
assert!(root_place.projection.is_none());
let (might_be_alive, will_be_dropped) = match root_place.base {
PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}) => {
(true, false)
}
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(_), .. })) => {
PlaceBase::Static(box Static {
kind: StaticKind::Static(_),
..
}) => {
// Thread-locals might be dropped after the function exits, but
// "true" statics will never be.
(true, self.is_place_thread_local(&root_place))
(true, self.is_place_thread_local(root_place))
}
Place::Base(PlaceBase::Local(_)) => {
PlaceBase::Local(_) => {
// Locals are always dropped at function exit, and if they
// have a destructor it would've been called already.
(false, self.locals_are_invalidated_at_exit)
}
Place::Projection(..) => {
bug!("root of {:?} is a projection ({:?})?", place, root_place)
}
};
if !will_be_dropped {
@ -1563,7 +1571,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self,
location: Location,
desired_action: InitializationRequiringAction,
place_span: (&Place<'tcx>, Span),
place_span: (PlaceRef<'cx, 'tcx>, Span),
flow_state: &Flows<'cx, 'tcx>,
) {
let maybe_uninits = &flow_state.uninits;
@ -1631,7 +1639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self,
location: Location,
desired_action: InitializationRequiringAction,
place_span: (&Place<'tcx>, Span),
place_span: (PlaceRef<'cx, 'tcx>, Span),
flow_state: &Flows<'cx, 'tcx>,
) {
let maybe_uninits = &flow_state.uninits;
@ -1686,25 +1694,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// An Err result includes a tag indicated why the search failed.
/// Currently this can only occur if the place is built off of a
/// static variable, as we do not track those in the MoveData.
fn move_path_closest_to<'a>(
fn move_path_closest_to(
&mut self,
place: &'a Place<'tcx>,
) -> Result<(&'a Place<'tcx>, MovePathIndex), NoMovePathFound> where 'cx: 'a {
let mut last_prefix = place;
place: PlaceRef<'cx, 'tcx>,
) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
let mut last_prefix = place.base;
for prefix in self.prefixes(place, PrefixSet::All) {
if let Some(mpi) = self.move_path_for_place(prefix) {
return Ok((prefix, mpi));
}
last_prefix = prefix;
last_prefix = prefix.base;
}
match *last_prefix {
Place::Base(PlaceBase::Local(_)) => panic!("should have move path for every Local"),
Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
Place::Base(PlaceBase::Static(_)) => Err(NoMovePathFound::ReachedStatic),
match last_prefix {
PlaceBase::Local(_) => panic!("should have move path for every Local"),
PlaceBase::Static(_) => Err(NoMovePathFound::ReachedStatic),
}
}
fn move_path_for_place(&mut self, place: &Place<'tcx>) -> Option<MovePathIndex> {
fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option<MovePathIndex> {
// If returns None, then there is no move path corresponding
// to a direct owner of `place` (which means there is nothing
// that borrowck tracks for its analysis).
@ -1718,94 +1728,97 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn check_if_assigned_path_is_moved(
&mut self,
location: Location,
(place, span): (&Place<'tcx>, Span),
(place, span): (&'cx Place<'tcx>, Span),
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 = place;
loop {
match *place {
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
// assigning to `x` does not require `x` be initialized.
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 {
ProjectionElem::Index(_/*operand*/) |
ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid.
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
// assigning to (P->variant) is okay if assigning to `P` is okay
//
// FIXME: is this true even if P is a adt with a dtor?
{ }
// assigning to (*P) requires P to be initialized
ProjectionElem::Deref => {
self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use,
(PlaceRef {
base: &place.base,
projection: base,
}, span), flow_state);
// (base initialized; no need to
// recur further)
break;
}
Place::Projection(ref proj) => {
let Projection { ref base, ref elem } = **proj;
match *elem {
ProjectionElem::Index(_/*operand*/) |
ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid.
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
// assigning to (P->variant) is okay if assigning to `P` is okay
//
// FIXME: is this true even if P is a adt with a dtor?
{ }
// assigning to (*P) requires P to be initialized
ProjectionElem::Deref => {
self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use,
(base, span), flow_state);
ProjectionElem::Subslice { .. } => {
panic!("we don't allow assignments to subslices, location: {:?}",
location);
}
ProjectionElem::Field(..) => {
// 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;
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,
}, span), flow_state);
// (base initialized; no need to
// recur further)
break;
}
ProjectionElem::Subslice { .. } => {
panic!("we don't allow assignments to subslices, location: {:?}",
location);
}
// Once `let s; s.x = V; read(s.x);`,
// is allowed, remove this match arm.
ty::Adt(..) | ty::Tuple(..) => {
check_parent_of_field(self, location, PlaceRef {
base: &place.base,
projection: base,
}, span, flow_state);
ProjectionElem::Field(..) => {
// if type of `P` has a dtor, then
// assigning to `P.f` requires `P` itself
// be already initialized
let tcx = self.infcx.tcx;
match base.ty(self.body, tcx).ty.sty {
ty::Adt(def, _) if def.has_dtor(tcx) => {
self.check_if_path_or_subpath_is_moved(
location, InitializationRequiringAction::Assignment,
(base, span), flow_state);
// (base initialized; no need to
// recur further)
break;
}
// Once `let s; s.x = V; read(s.x);`,
// is allowed, remove this match arm.
ty::Adt(..) | ty::Tuple(..) => {
check_parent_of_field(self, location, base, span, flow_state);
if let Some(local) = place.base_local() {
// rust-lang/rust#21232,
// #54499, #54986: during
// period where we reject
// partial initialization, do
// not complain about
// unnecessary `mut` on an
// attempt to do a partial
// initialization.
self.used_mut.insert(local);
}
}
_ => {}
if let PlaceBase::Local(local) = place.base {
// rust-lang/rust#21232,
// #54499, #54986: during
// period where we reject
// partial initialization, do
// not complain about
// unnecessary `mut` on an
// attempt to do a partial
// initialization.
self.used_mut.insert(local);
}
}
}
place = base;
_ => {}
}
}
}
place_projection = base;
}
fn check_parent_of_field<'cx, 'tcx>(
this: &mut MirBorrowckCtxt<'cx, 'tcx>,
location: Location,
base: &Place<'tcx>,
base: PlaceRef<'cx, 'tcx>,
span: Span,
flow_state: &Flows<'cx, 'tcx>,
) {
@ -1866,7 +1879,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// no move out from an earlier location) then this is an attempt at initialization
// of the union - we should error in that case.
let tcx = this.infcx.tcx;
if let ty::Adt(def, _) = base.ty(this.body, tcx).ty.sty {
if let ty::Adt(def, _) =
Place::ty_from(base.base, base.projection, this.body, tcx).ty.sty
{
if def.is_union() {
if this.move_data.path_map[mpi].iter().any(|moi| {
this.move_data.moves[*moi].source.is_predecessor_of(
@ -1911,7 +1926,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// partial initialization, do not complain about mutability
// errors except for actual mutation (as opposed to an attempt
// to do a partial initialization).
let previously_initialized = if let Some(local) = place.base_local() {
let previously_initialized = if let PlaceBase::Local(local) = place.base {
self.is_local_ever_initialized(local, flow_state).is_some()
} else {
true
@ -1927,7 +1942,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
BorrowKind::Mut { .. } => is_local_mutation_allowed,
BorrowKind::Shared | BorrowKind::Shallow => unreachable!(),
};
match self.is_mutable(place, is_local_mutation_allowed) {
match self.is_mutable(&place.base, &place.projection, is_local_mutation_allowed) {
Ok(root_place) => {
self.add_used_mut(root_place, flow_state);
return false;
@ -1939,7 +1954,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
match self.is_mutable(place, is_local_mutation_allowed) {
match self.is_mutable(&place.base, &place.projection, is_local_mutation_allowed) {
Ok(root_place) => {
self.add_used_mut(root_place, flow_state);
return false;
@ -1960,7 +1975,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => {
if let (Err(_place_err), true) = (
self.is_mutable(place, is_local_mutation_allowed),
self.is_mutable(&place.base, &place.projection, is_local_mutation_allowed),
self.errors_buffer.is_empty()
) {
if self.infcx.tcx.migrate_borrowck() {
@ -1981,7 +1996,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.report_mutability_error(
place,
span,
_place_err,
PlaceRef {
base: _place_err.0,
projection: _place_err.1,
},
error_access,
location,
);
@ -2015,7 +2033,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.report_mutability_error(
place,
span,
the_place_err,
PlaceRef {
base: the_place_err.0,
projection: the_place_err.1,
},
error_access,
location,
);
@ -2044,7 +2065,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) {
match root_place {
RootPlace {
place: Place::Base(PlaceBase::Local(local)),
place_base: PlaceBase::Local(local),
place_projection: None,
is_local_mutation_allowed,
} => {
// If the local may have been initialized, and it is now currently being
@ -2057,19 +2079,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
RootPlace {
place: _,
place_base: _,
place_projection: _,
is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
} => {}
RootPlace {
place: place @ Place::Projection(_),
place_base,
place_projection: place_projection @ Some(_),
is_local_mutation_allowed: _,
} => {
if let Some(field) = self.is_upvar_field_projection(place) {
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
base: &place_base,
projection: &place_projection,
}) {
self.used_mut_upvars.push(field);
}
}
RootPlace {
place: Place::Base(PlaceBase::Static(..)),
place_base: PlaceBase::Static(..),
place_projection: None,
is_local_mutation_allowed: _,
} => {}
}
@ -2079,62 +2107,78 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Returns the root place if the place passed in is a projection.
fn is_mutable<'d>(
&self,
place: &'d Place<'tcx>,
place_base: &'d PlaceBase<'tcx>,
place_projection: &'d Option<Box<Projection<'tcx>>>,
is_local_mutation_allowed: LocalMutationIsAllowed,
) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> {
match *place {
Place::Base(PlaceBase::Local(local)) => {
let local = &self.body.local_decls[local];
) -> Result<RootPlace<'d, 'tcx>, (&'d PlaceBase<'tcx>, &'d Option<Box<Projection<'tcx>>>)> {
match (place_base, place_projection) {
(PlaceBase::Local(local), None) => {
let local = &self.body.local_decls[*local];
match local.mutability {
Mutability::Not => match is_local_mutation_allowed {
LocalMutationIsAllowed::Yes => Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
}),
LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
}),
LocalMutationIsAllowed::No => Err(place),
LocalMutationIsAllowed::No => Err((place_base, place_projection)),
},
Mutability::Mut => Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed,
}),
}
}
// The rules for promotion are made by `qualify_consts`, there wouldn't even be a
// `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
Place::Base(PlaceBase::Static(box Static{kind: StaticKind::Promoted(_), ..})) =>
(PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}), None) =>
Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed,
}),
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
if !self.infcx.tcx.is_mutable_static(def_id) {
Err(place)
(PlaceBase::Static(box Static {
kind: StaticKind::Static(def_id),
..
}), None) => {
if !self.infcx.tcx.is_mutable_static(*def_id) {
Err((place_base, place_projection))
} else {
Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed,
})
}
}
Place::Projection(ref proj) => {
(_, Some(ref proj)) => {
match proj.elem {
ProjectionElem::Deref => {
let base_ty = proj.base.ty(self.body, self.infcx.tcx).ty;
let base_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 {
ty::Ref(_, _, mutbl) => {
match mutbl {
// Shared borrowed data is never mutable
hir::MutImmutable => Err(place),
hir::MutImmutable => Err((place_base, place_projection)),
// Mutably borrowed data is mutable, but only if we have a
// unique path to the `&mut`
hir::MutMutable => {
let mode = match self.is_upvar_field_projection(place) {
let mode = match self.is_upvar_field_projection(PlaceRef {
base: &place_base,
projection: &place_projection,
}) {
Some(field)
if self.upvars[field.index()].by_ref =>
{
@ -2143,19 +2187,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
_ => LocalMutationIsAllowed::Yes,
};
self.is_mutable(&proj.base, mode)
self.is_mutable(place_base, &proj.base, mode)
}
}
}
ty::RawPtr(tnm) => {
match tnm.mutbl {
// `*const` raw pointers are not mutable
hir::MutImmutable => Err(place),
hir::MutImmutable => Err((place_base, place_projection)),
// `*mut` raw pointers are always mutable, regardless of
// context. The users have to check by themselves.
hir::MutMutable => {
Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed,
})
}
@ -2163,7 +2208,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
// `Box<T>` owns its content, so mutable if its location is mutable
_ if base_ty.is_box() => {
self.is_mutable(&proj.base, is_local_mutation_allowed)
self.is_mutable(place_base, &proj.base, is_local_mutation_allowed)
}
// Deref should only be for reference, pointers or boxes
_ => bug!("Deref of unexpected type: {:?}", base_ty),
@ -2176,17 +2221,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
let upvar_field_projection = self.is_upvar_field_projection(PlaceRef {
base: &place_base,
projection: &place_projection,
});
if let Some(field) = upvar_field_projection {
let upvar = &self.upvars[field.index()];
debug!(
"upvar.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
upvar, is_local_mutation_allowed, place
"upvar.mutability={:?} local_mutation_is_allowed={:?} \
place={:?} {:?}",
upvar, is_local_mutation_allowed, place_base, place_projection
);
match (upvar.mutability, is_local_mutation_allowed) {
(Mutability::Not, LocalMutationIsAllowed::No)
| (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => {
Err(place)
Err((place_base, place_projection))
}
(Mutability::Not, LocalMutationIsAllowed::Yes)
| (Mutability::Mut, _) => {
@ -2216,15 +2265,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// });
// }
// ```
let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?;
let _ = self.is_mutable(place_base,
&proj.base,
is_local_mutation_allowed)?;
Ok(RootPlace {
place,
place_base,
place_projection,
is_local_mutation_allowed,
})
}
}
} else {
self.is_mutable(&proj.base, is_local_mutation_allowed)
self.is_mutable(place_base, &proj.base, is_local_mutation_allowed)
}
}
}
@ -2236,33 +2288,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
pub fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
let (place, by_ref) = if let Place::Projection(ref proj) = place {
if let ProjectionElem::Deref = proj.elem {
(&proj.base, true)
} else {
(place, false)
}
} else {
(place, false)
};
pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option<Field> {
let mut place_projection = place_ref.projection;
let mut by_ref = false;
match place {
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Field(field, _ty) => {
let tcx = self.infcx.tcx;
let base_ty = proj.base.ty(self.body, tcx).ty;
if let Some(box Projection {
base,
elem: ProjectionElem::Deref,
}) = place_projection {
place_projection = &base;
by_ref = true;
}
if (base_ty.is_closure() || base_ty.is_generator()) &&
(!by_ref || self.upvars[field.index()].by_ref)
{
Some(field)
} else {
None
}
},
_ => None,
match place_projection {
Some(box Projection {
base,
elem: ProjectionElem::Field(field, _ty),
}) => {
let tcx = self.infcx.tcx;
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) {
Some(*field)
} else {
None
}
}
_ => None,
}
}

View file

@ -91,7 +91,10 @@ 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)),
Place {
base: PlaceBase::Local(local),
projection: None,
},
box Rvalue::Use(Operand::Move(move_from)),
)) = self.body.basic_blocks()[location.block]
.statements
@ -128,7 +131,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
let move_spans = self.move_spans(&original_path, location);
let move_spans = self.move_spans(original_path.as_place_ref(), location);
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
use_spans: move_spans,
original_path,
@ -157,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let from_simple_let = match_place.is_none();
let match_place = match_place.as_ref().unwrap_or(move_from);
match self.move_data.rev_lookup.find(match_place) {
match self.move_data.rev_lookup.find(match_place.as_place_ref()) {
// Error with the match place
LookupResult::Parent(_) => {
for ge in &mut *grouped_errors {
@ -189,7 +192,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
// Error with the pattern
LookupResult::Exact(_) => {
let mpi = match self.move_data.rev_lookup.find(move_from) {
let mpi = match self.move_data.rev_lookup.find(move_from.as_place_ref()) {
LookupResult::Parent(Some(mpi)) => mpi,
// move_from should be a projection from match_place.
_ => unreachable!("Probably not unreachable..."),
@ -239,7 +242,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
debug!("report: original_path={:?} span={:?}, kind={:?} \
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
self.is_upvar_field_projection(original_path));
self.is_upvar_field_projection(original_path.as_place_ref()));
(
match kind {
IllegalMoveOriginKind::Static => {
@ -273,20 +276,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
place: &Place<'tcx>,
span: Span
) -> DiagnosticBuilder<'a> {
let mut base_static = place;
loop {
match base_static {
Place::Base(_) => break,
Place::Projection(box Projection { base, .. }) => base_static = base,
}
}
let description = if let Place::Base(_) = place {
format!("static item `{}`", self.describe_place(place).unwrap())
let description = if place.projection.is_none() {
format!("static item `{}`", self.describe_place(place.as_place_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,
};
format!(
"`{:?}` as `{:?}` is a static item",
self.describe_place(place).unwrap(),
self.describe_place(place.as_place_ref()).unwrap(),
self.describe_place(base_static).unwrap(),
)
};
@ -304,16 +308,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// borrow to provide feedback about why this
// was a move rather than a copy.
let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty;
let upvar_field = self.prefixes(&move_place, PrefixSet::All)
let upvar_field = self.prefixes(move_place.as_place_ref(), PrefixSet::All)
.find_map(|p| self.is_upvar_field_projection(p));
let deref_base = match deref_target_place {
Place::Projection(box Projection { base, elem: ProjectionElem::Deref }) => base,
let deref_base = match deref_target_place.projection {
Some(box Projection { ref base, elem: ProjectionElem::Deref }) => PlaceRef {
base: &deref_target_place.base,
projection: base,
},
_ => bug!("deref_target_place is not a deref projection"),
};
if let Place::Base(PlaceBase::Local(local)) = *deref_base {
let decl = &self.body.local_decls[local];
if let PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} = deref_base {
let decl = &self.body.local_decls[*local];
if decl.is_ref_for_guard() {
let mut err = self.cannot_move_out_of(
span,
@ -353,9 +363,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvar_name = upvar.name;
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
let place_name = self.describe_place(move_place).unwrap();
let place_name = self.describe_place(move_place.as_place_ref()).unwrap();
let place_description = if self.is_upvar_field_projection(move_place).is_some() {
let place_description = if self
.is_upvar_field_projection(move_place.as_place_ref())
.is_some()
{
format!("`{}`, a {}", place_name, capture_description)
} else {
format!(
@ -379,7 +392,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
_ => {
let source = self.borrowed_content_source(deref_base);
match (self.describe_place(move_place), source.describe_for_named_place()) {
match (
self.describe_place(move_place.as_place_ref()),
source.describe_for_named_place(),
) {
(Some(place_desc), Some(source_desc)) => {
self.cannot_move_out_of(
span,
@ -439,7 +455,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(&move_from) {
let place_desc = match self.describe_place(move_from.as_place_ref()) {
Some(desc) => format!("`{}`", desc),
None => format!("value"),
};
@ -467,7 +483,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
let span = use_spans.var_or_use();
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(original_path) {
let place_desc = match self.describe_place(original_path.as_place_ref()) {
Some(desc) => format!("`{}`", desc),
None => format!("value"),
};

View file

@ -2,7 +2,9 @@ use core::unicode::property::Pattern_White_Space;
use rustc::hir;
use rustc::hir::Node;
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
use rustc::mir::{Mutability, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind};
use rustc::mir::{
Mutability, Place, PlaceRef, PlaceBase, Projection, ProjectionElem, Static, StaticKind
};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
@ -25,7 +27,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&mut self,
access_place: &Place<'tcx>,
span: Span,
the_place_err: &Place<'tcx>,
the_place_err: PlaceRef<'cx, 'tcx>,
error_access: AccessKind,
location: Location,
) {
@ -40,13 +42,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let item_msg;
let reason;
let mut opt_source = None;
let access_place_desc = self.describe_place(access_place);
let access_place_desc = self.describe_place(access_place.as_place_ref());
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
match the_place_err {
Place::Base(PlaceBase::Local(local)) => {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} => {
item_msg = format!("`{}`", access_place_desc.unwrap());
if let Place::Base(PlaceBase::Local(_)) = access_place {
if let Place {
base: PlaceBase::Local(_),
projection: None,
} = access_place {
reason = ", as it is not declared as mutable".to_string();
} else {
let name = self.body.local_decls[*local]
@ -56,16 +64,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Place::Projection(box Projection {
base,
elem: ProjectionElem::Field(upvar_index, _),
}) => {
PlaceRef {
base: _,
projection:
Some(box Projection {
base,
elem: ProjectionElem::Field(upvar_index, _),
}),
} => {
debug_assert!(is_closure_or_generator(
base.ty(self.body, self.infcx.tcx).ty
Place::ty_from(&the_place_err.base, &base, self.body, self.infcx.tcx).ty
));
item_msg = format!("`{}`", access_place_desc.unwrap());
if self.is_upvar_field_projection(access_place).is_some() {
if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
let name = self.upvars[upvar_index.index()].name;
@ -73,26 +85,38 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Place::Projection(box Projection {
base,
elem: ProjectionElem::Deref,
}) => {
if *base == Place::Base(PlaceBase::Local(Local::new(1))) &&
PlaceRef {
base: _,
projection:
Some(box Projection {
base,
elem: ProjectionElem::Deref,
}),
} => {
if the_place_err.base == &PlaceBase::Local(Local::new(1)) &&
base.is_none() &&
!self.upvars.is_empty() {
item_msg = format!("`{}`", access_place_desc.unwrap());
debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
debug_assert!(is_closure_or_generator(
the_place_err.ty(self.body, self.infcx.tcx).ty
Place::ty_from(
the_place_err.base,
the_place_err.projection,
self.body,
self.infcx.tcx
)
.ty
));
reason = if self.is_upvar_field_projection(access_place).is_some() {
", as it is a captured variable in a `Fn` closure".to_string()
} else {
", as `Fn` closures cannot mutate their captured variables".to_string()
}
reason =
if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() {
", as it is a captured variable in a `Fn` closure".to_string()
} else {
", as `Fn` closures cannot mutate their captured variables".to_string()
}
} else if {
if let Place::Base(PlaceBase::Local(local)) = *base {
self.body.local_decls[local].is_ref_for_guard()
if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) {
self.body.local_decls[*local].is_ref_for_guard()
} else {
false
}
@ -100,7 +124,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
item_msg = format!("`{}`", access_place_desc.unwrap());
reason = ", as it is immutable for the pattern guard".to_string();
} else {
let source = self.borrowed_content_source(base);
let source = self.borrowed_content_source(PlaceRef {
base: the_place_err.base,
projection: base,
});
let pointer_type = source.describe_for_immutable_place();
opt_source = Some(source);
if let Some(desc) = access_place_desc {
@ -119,11 +146,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) =>
unreachable!(),
PlaceRef {
base:
PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}),
projection: None,
} => unreachable!(),
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. })) => {
if let Place::Base(PlaceBase::Static(_)) = access_place {
PlaceRef {
base:
PlaceBase::Static(box Static {
kind: StaticKind::Static(def_id),
..
}),
projection: None,
} => {
if let Place {
base: PlaceBase::Static(_),
projection: None,
} = access_place {
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
reason = String::new();
} else {
@ -133,22 +176,36 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Place::Projection(box Projection {
PlaceRef {
base: _,
elem: ProjectionElem::Index(_),
})
| Place::Projection(box Projection {
projection:
Some(box Projection {
base: _,
elem: ProjectionElem::Index(_),
}),
}
| PlaceRef {
base: _,
elem: ProjectionElem::ConstantIndex { .. },
})
| Place::Projection(box Projection {
projection:
Some(box Projection {
base: _,
elem: ProjectionElem::ConstantIndex { .. },
}),
}
| PlaceRef {
base: _,
elem: ProjectionElem::Subslice { .. },
})
| Place::Projection(box Projection {
projection: Some(box Projection {
base: _,
elem: ProjectionElem::Subslice { .. },
}),
}
| PlaceRef {
base: _,
elem: ProjectionElem::Downcast(..),
}) => bug!("Unexpected immutable place."),
projection: Some(box Projection {
base: _,
elem: ProjectionElem::Downcast(..),
}),
} => bug!("Unexpected immutable place."),
}
debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason);
@ -187,7 +244,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
format!(
"mutable borrow occurs due to use of `{}` in closure",
// always Some() if the message is printed.
self.describe_place(access_place).unwrap_or_default(),
self.describe_place(access_place.as_place_ref()).unwrap_or_default(),
)
);
borrow_span
@ -203,21 +260,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// something like `*((*_1).0`. The local that we get will be a reference to the
// struct we've got a field access of (it must be a reference since there's a deref
// after the field access).
Place::Projection(box Projection {
base: Place::Projection(box Projection {
base: Place::Projection(box Projection {
base,
elem: ProjectionElem::Deref,
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::Field(field, _),
elem: ProjectionElem::Deref,
}),
elem: ProjectionElem::Deref,
}) => {
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
if let Some((span, message)) = annotate_struct_field(
self.infcx.tcx,
base.ty(self.body, self.infcx.tcx).ty,
Place::ty_from(&base, &base_proj, self.body, self.infcx.tcx).ty,
field,
) {
err.span_suggestion(
@ -230,43 +290,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
},
// Suggest removing a `&mut` from the use of a mutable reference.
Place::Base(PlaceBase::Local(local))
if {
self.body.local_decls.get(*local).map(|local_decl| {
if let ClearCrossCrate::Set(
mir::BindingForm::ImplicitSelf(kind)
) = local_decl.is_user_variable.as_ref().unwrap() {
// Check if the user variable is a `&mut self` and we can therefore
// suggest removing the `&mut`.
//
// Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them.
*kind == mir::ImplicitSelfKind::MutRef
} else if Some(kw::SelfLower) == local_decl.name {
// Otherwise, check if the name is the self kewyord - in which case
// we have an explicit self. Do the same thing in this case and check
// for a `self: &mut Self` to suggest removing the `&mut`.
if let ty::Ref(
_, _, hir::Mutability::MutMutable
) = local_decl.ty.sty {
true
} else {
false
}
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} if {
self.body.local_decls.get(*local).map(|local_decl| {
if let ClearCrossCrate::Set(
mir::BindingForm::ImplicitSelf(kind)
) = local_decl.is_user_variable.as_ref().unwrap() {
// Check if the user variable is a `&mut self` and we can therefore
// suggest removing the `&mut`.
//
// Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them.
*kind == mir::ImplicitSelfKind::MutRef
} else if Some(kw::SelfLower) == local_decl.name {
// Otherwise, check if the name is the self kewyord - in which case
// we have an explicit self. Do the same thing in this case and check
// for a `self: &mut Self` to suggest removing the `&mut`.
if let ty::Ref(
_, _, hir::Mutability::MutMutable
) = local_decl.ty.sty {
true
} else {
false
}
}).unwrap_or(false)
} =>
{
} else {
false
}
}).unwrap_or(false)
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
err.span_label(span, "try removing `&mut` here");
},
// We want to suggest users use `let mut` for local (user
// variable) mutations...
Place::Base(PlaceBase::Local(local))
if self.body.local_decls[*local].can_be_made_mutable() => {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} 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`,
// or `&mut self` (such variables are simply not
@ -284,12 +347,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
// Also suggest adding mut for upvars
Place::Projection(box Projection {
PlaceRef {
base,
elem: ProjectionElem::Field(upvar_index, _),
}) => {
projection: Some(box Projection {
base: proj_base,
elem: ProjectionElem::Field(upvar_index, _),
}),
} => {
debug_assert!(is_closure_or_generator(
base.ty(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));
@ -317,8 +383,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// complete hack to approximate old AST-borrowck
// diagnostic: if the span starts with a mutable borrow of
// a local variable, then just suggest the user remove it.
Place::Base(PlaceBase::Local(_))
if {
PlaceRef {
base: PlaceBase::Local(_),
projection: None,
} if {
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
snippet.starts_with("&mut ")
} else {
@ -330,10 +398,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_label(span, "try removing `&mut` here");
}
Place::Projection(box Projection {
base: Place::Base(PlaceBase::Local(local)),
elem: ProjectionElem::Deref,
}) if {
PlaceRef {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
}),
} if {
if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
self.body.local_decls[*local].is_user_variable
{
@ -354,10 +425,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
//
// FIXME: can this case be generalized to work for an
// arbitrary base for the projection?
Place::Projection(box Projection {
base: Place::Base(PlaceBase::Local(local)),
elem: ProjectionElem::Deref,
}) if self.body.local_decls[*local].is_user_variable.is_some() =>
PlaceRef {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
}),
} if self.body.local_decls[*local].is_user_variable.is_some() =>
{
let local_decl = &self.body.local_decls[*local];
let suggestion = match local_decl.is_user_variable.as_ref().unwrap() {
@ -434,10 +508,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Place::Projection(box Projection {
PlaceRef {
base,
elem: ProjectionElem::Deref,
}) if *base == Place::Base(PlaceBase::Local(Local::new(1))) &&
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
}),
// FIXME document what is this 1 magic number about
} if *base == PlaceBase::Local(Local::new(1)) &&
!self.upvars.is_empty() =>
{
err.span_label(span, format!("cannot {ACT}", ACT = act));
@ -447,10 +525,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
);
}
Place::Projection(box Projection {
PlaceRef {
base: _,
elem: ProjectionElem::Deref,
}) => {
projection: Some(box Projection {
base: _,
elem: ProjectionElem::Deref,
}),
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
match opt_source {

View file

@ -128,7 +128,10 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
// When we see `X = ...`, then kill borrows of
// `(*X).foo` and so forth.
if let Some(all_facts) = self.all_facts {
if let Place::Base(PlaceBase::Local(temp)) = place {
if let Place {
base: PlaceBase::Local(temp),
projection: None,
} = place {
if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) {
all_facts.killed.reserve(borrow_indices.len());
for &borrow_index in borrow_indices {

View file

@ -7,7 +7,7 @@ use crate::borrow_check::nll::ConstraintDescription;
use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
use rustc::mir::{
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase,
Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind,
Rvalue, Statement, StatementKind, TerminatorKind,
};
use rustc::ty::{self, TyCtxt};
use rustc::ty::adjustment::{PointerCast};
@ -252,7 +252,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(Cause::LiveVar(local, location)) => {
let span = body.source_info(location).span;
let spans = self
.move_spans(&Place::from(local), location)
.move_spans(Place::from(local).as_place_ref(), location)
.or_else(|| self.borrow_spans(span, location));
let borrow_location = location;
@ -272,7 +272,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut should_note_order = false;
if body.local_decls[local].name.is_some() {
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
if let Place::Base(PlaceBase::Local(borrowed_local)) = place {
if let Place {
base: PlaceBase::Local(borrowed_local),
projection: None,
} = place {
if body.local_decls[*borrowed_local].name.is_some()
&& local != *borrowed_local
{
@ -301,7 +304,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
region,
);
if let Some(region_name) = region_name {
let opt_place_desc = self.describe_place(&borrow.borrowed_place);
let opt_place_desc =
self.describe_place(borrow.borrowed_place.as_place_ref());
BorrowExplanation::MustBeValidFor {
category,
from_closure,
@ -489,8 +493,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Just point to the function, to reduce the chance of overlapping spans.
let function_span = match func {
Operand::Constant(c) => c.span,
Operand::Copy(Place::Base(PlaceBase::Local(l))) |
Operand::Move(Place::Base(PlaceBase::Local(l))) => {
Operand::Copy(Place {
base: PlaceBase::Local(l),
projection: None,
}) |
Operand::Move(Place {
base: PlaceBase::Local(l),
projection: None,
}) => {
let local_decl = &self.body.local_decls[*l];
if local_decl.name.is_none() {
local_decl.source_info.span
@ -531,7 +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::Base(PlaceBase::Local(local)), _),
kind: StatementKind::Assign(Place {
base: PlaceBase::Local(local),
projection: None,
}, _),
..
}) = stmt
{
@ -555,13 +568,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// The only kind of statement that we care about is assignments...
if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
let into = match place {
Place::Base(PlaceBase::Local(into)) => into,
Place::Projection(box Projection {
base: Place::Base(PlaceBase::Local(into)),
elem: ProjectionElem::Deref,
}) => into,
_ => {
let into = match place.local_or_deref_local() {
Some(into) => into,
None => {
// Continue at the next location.
queue.push(current_location.successor_within_block());
continue;
@ -572,11 +581,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// If we see a use, we should check whether it is our data, and if so
// update the place that we're looking for to that new place.
Rvalue::Use(operand) => match operand {
Operand::Copy(Place::Base(PlaceBase::Local(from)))
| Operand::Move(Place::Base(PlaceBase::Local(from)))
Operand::Copy(Place {
base: PlaceBase::Local(from),
projection: None,
})
| Operand::Move(Place {
base: PlaceBase::Local(from),
projection: None,
})
if *from == target =>
{
target = *into;
target = into;
}
_ => {}
},
@ -585,8 +600,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Rvalue::Cast(
CastKind::Pointer(PointerCast::Unsize), operand, ty
) => match operand {
Operand::Copy(Place::Base(PlaceBase::Local(from)))
| Operand::Move(Place::Base(PlaceBase::Local(from)))
Operand::Copy(Place {
base: PlaceBase::Local(from),
projection: None,
})
| Operand::Move(Place {
base: PlaceBase::Local(from),
projection: None,
})
if *from == target =>
{
debug!("was_captured_by_trait_object: ty={:?}", ty);
@ -616,7 +637,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("was_captured_by_trait_object: terminator={:?}", terminator);
if let TerminatorKind::Call {
destination: Some((Place::Base(PlaceBase::Local(dest)), block)),
destination: Some((Place {
base: PlaceBase::Local(dest),
projection: None,
}, block)),
args,
..
} = &terminator.kind
@ -627,7 +651,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
if let Operand::Move(Place::Base(PlaceBase::Local(potential))) = arg {
if let Operand::Move(Place {
base: PlaceBase::Local(potential),
projection: None,
}) = arg {
*potential == target
} else {
false

View file

@ -499,13 +499,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
};
// FIXME use place_projection.is_empty() when is available
if let Place::Base(_) = place {
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(_),
..
})) => true,
Place {
base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}),
projection: None,
} => true,
_ => false,
};
@ -1345,15 +1348,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// of lowering. Assignments to other sorts of places *are* interesting
// though.
let category = match *place {
Place::Base(PlaceBase::Local(RETURN_PLACE)) => if let BorrowCheckContext {
Place {
base: PlaceBase::Local(RETURN_PLACE),
projection: None,
} => if let BorrowCheckContext {
universal_regions:
UniversalRegions {
defining_ty: DefiningTy::Const(def_id, _),
..
},
..
} = self.borrowck_context
{
} = self.borrowck_context {
if tcx.is_static(*def_id) {
ConstraintCategory::UseAsStatic
} else {
@ -1362,8 +1367,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} else {
ConstraintCategory::Return
},
Place::Base(PlaceBase::Local(l))
if !body.local_decls[l].is_user_variable.is_some() => {
Place {
base: PlaceBase::Local(l),
projection: None,
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
_ => ConstraintCategory::Assignment,
@ -1647,7 +1654,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some((ref dest, _target_block)) => {
let dest_ty = dest.ty(body, tcx).ty;
let category = match *dest {
Place::Base(PlaceBase::Local(RETURN_PLACE)) => {
Place {
base: PlaceBase::Local(RETURN_PLACE),
projection: None,
} => {
if let BorrowCheckContext {
universal_regions:
UniversalRegions {
@ -1666,8 +1676,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Return
}
}
Place::Base(PlaceBase::Local(l))
if !body.local_decls[l].is_user_variable.is_some() => {
Place {
base: PlaceBase::Local(l),
projection: None,
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
_ => ConstraintCategory::Assignment,
@ -2400,19 +2412,19 @@ 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_place = borrowed_place;
let mut borrowed_projection = &borrowed_place.projection;
debug!(
"add_reborrow_constraint({:?}, {:?}, {:?})",
location, borrow_region, borrowed_place
);
while let Place::Projection(box Projection { base, elem }) = borrowed_place {
debug!("add_reborrow_constraint - iteration {:?}", borrowed_place);
while let Some(box proj) = borrowed_projection {
debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection);
match *elem {
match proj.elem {
ProjectionElem::Deref => {
let tcx = self.infcx.tcx;
let base_ty = base.ty(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 {
@ -2477,7 +2489,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// The "propagate" case. We need to check that our base is valid
// for the borrow's lifetime.
borrowed_place = base;
borrowed_projection = &proj.base;
}
}

View file

@ -50,7 +50,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
body,
&borrowed.borrowed_place,
borrowed.kind,
place,
place.as_place_ref(),
access,
places_conflict::PlaceConflictBias::Overlap,
) {

View file

@ -55,7 +55,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
for proj in place_projection {
if proj.elem == ProjectionElem::Deref {
let ty = proj.base.ty(body, tcx).ty;
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

View file

@ -3,8 +3,8 @@ use crate::borrow_check::Overlap;
use crate::borrow_check::{Deep, Shallow, AccessDepth};
use rustc::hir;
use rustc::mir::{
BorrowKind, Body, Place, PlaceBase, Projection, ProjectionElem, ProjectionsIter,
StaticKind
Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
StaticKind,
};
use rustc::ty::{self, TyCtxt};
use std::cmp::max;
@ -36,7 +36,7 @@ crate fn places_conflict<'tcx>(
body,
borrow_place,
BorrowKind::Mut { allow_two_phase_borrow: true },
access_place,
access_place.as_place_ref(),
AccessDepth::Deep,
bias,
)
@ -51,7 +51,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
body: &Body<'tcx>,
borrow_place: &Place<'tcx>,
borrow_kind: BorrowKind,
access_place: &Place<'tcx>,
access_place: PlaceRef<'_, 'tcx>,
access: AccessDepth,
bias: PlaceConflictBias,
) -> bool {
@ -62,8 +62,14 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
// This Local/Local case is handled by the more general code below, but
// it's so common that it's a speed win to check for it first.
if let Place::Base(PlaceBase::Local(l1)) = borrow_place {
if let Place::Base(PlaceBase::Local(l2)) = access_place {
if let Place {
base: PlaceBase::Local(l1),
projection: None,
} = borrow_place {
if let PlaceRef {
base: PlaceBase::Local(l2),
projection: None,
} = access_place {
return l1 == l2;
}
}
@ -175,7 +181,7 @@ fn place_components_conflict<'tcx>(
// 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_c, access_c, bias) {
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.
@ -214,7 +220,7 @@ fn place_components_conflict<'tcx>(
let base = &borrow_c.base;
let elem = &borrow_c.elem;
let base_ty = base.ty(body, tcx).ty;
let base_ty = Place::ty_from(borrow_base, base, body, tcx).ty;
match (elem, &base_ty.sty, access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
@ -368,6 +374,7 @@ fn place_base_conflict<'tcx>(
fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pi1_base: &PlaceBase<'tcx>,
pi1: &Projection<'tcx>,
pi2: &Projection<'tcx>,
bias: PlaceConflictBias,
@ -384,7 +391,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint
} else {
let ty = pi1.base.ty(body, tcx).ty;
let ty = Place::ty_from(pi1_base, &pi1.base, body, tcx).ty;
match ty.sty {
ty::Adt(def, _) if def.is_union() => {
// Different fields of a union, we are basically stuck.

View file

@ -11,26 +11,23 @@ use super::MirBorrowckCtxt;
use rustc::hir;
use rustc::ty::{self, TyCtxt};
use rustc::mir::{Body, Place, PlaceBase, ProjectionElem};
use rustc::mir::{Body, Place, PlaceBase, PlaceRef, ProjectionElem};
pub trait IsPrefixOf<'tcx> {
fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
pub trait IsPrefixOf<'cx, 'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool;
}
impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
let mut cursor = other;
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 == cursor {
return true;
if self.projection == cursor {
return self.base == other.base;
}
match *cursor {
Place::Base(PlaceBase::Local(_)) |
Place::Base(PlaceBase::Static(_)) => return false,
Place::Projection(ref proj) => {
cursor = &proj.base;
}
match cursor {
None => return false,
Some(proj) => cursor = &proj.base,
}
}
}
@ -40,7 +37,7 @@ pub(super) struct Prefixes<'cx, 'tcx> {
body: &'cx Body<'tcx>,
tcx: TyCtxt<'tcx>,
kind: PrefixSet,
next: Option<&'cx Place<'tcx>>,
next: Option<(PlaceRef<'cx, 'tcx>)>,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -59,9 +56,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Returns an iterator over the prefixes of `place`
/// (inclusive) from longest to smallest, potentially
/// terminating the iteration early based on `kind`.
pub(super) fn prefixes(&self, place: &'cx Place<'tcx>, kind: PrefixSet) -> Prefixes<'cx, 'tcx> {
pub(super) fn prefixes(
&self,
place_ref: PlaceRef<'cx, 'tcx>,
kind: PrefixSet,
) -> Prefixes<'cx, 'tcx> {
Prefixes {
next: Some(place),
next: Some(place_ref),
kind,
body: self.body,
tcx: self.infcx.tcx,
@ -70,7 +71,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
type Item = &'cx Place<'tcx>;
type Item = PlaceRef<'cx, 'tcx>;
fn next(&mut self) -> Option<Self::Item> {
let mut cursor = self.next?;
@ -80,27 +81,42 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
// downcasts here, but may return a base of a downcast).
'cursor: loop {
let proj = match *cursor {
Place::Base(PlaceBase::Local(_)) | // search yielded this leaf
Place::Base(PlaceBase::Static(_)) => {
let proj = match &cursor {
PlaceRef {
base: PlaceBase::Local(_),
projection: None,
}
| // search yielded this leaf
PlaceRef {
base: PlaceBase::Static(_),
projection: None,
} => {
self.next = None;
return Some(cursor);
}
Place::Projection(ref proj) => proj,
PlaceRef {
base: _,
projection: Some(proj),
} => proj,
};
match proj.elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
// FIXME: add union handling
self.next = Some(&proj.base);
// 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 = &proj.base;
cursor = PlaceRef {
base: cursor.base,
projection: &proj.base,
};
continue 'cursor;
}
ProjectionElem::Deref => {
@ -121,7 +137,10 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
PrefixSet::All => {
// all prefixes: just blindly enqueue the base
// of the projection
self.next = Some(&proj.base);
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}
PrefixSet::Supporting => {
@ -134,7 +153,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
// derefs, except we stop at the deref of a shared
// reference.
let ty = proj.base.ty(self.body, self.tcx).ty;
let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
match ty.sty {
ty::RawPtr(_) |
ty::Ref(
@ -152,12 +171,18 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
_, /*ty*/
hir::MutMutable,
) => {
self.next = Some(&proj.base);
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}
ty::Adt(..) if ty.is_box() => {
self.next = Some(&proj.base);
self.next = Some(PlaceRef {
base: cursor.base,
projection: &proj.base,
});
return Some(cursor);
}

View file

@ -59,7 +59,7 @@ impl GatherUsedMutsVisitor<'_, '_, '_> {
// be those that were never initialized - we will consider those as being used as
// they will either have been removed by unreachable code optimizations; or linted
// as unused variables.
if let Some(local) = into.base_local() {
if let PlaceBase::Local(local) = into.base {
let _ = self.never_initialized_mut_locals.remove(&local);
}
}
@ -90,7 +90,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
) {
match &statement.kind {
StatementKind::Assign(into, _) => {
if let Some(local) = into.base_local() {
if let PlaceBase::Local(local) = into.base {
debug!(
"visit_statement: statement={:?} local={:?} \
never_initialized_mut_locals={:?}",
@ -118,7 +118,10 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
"assignment of {:?} to {:?}, adding {:?} to used mutable set",
path.place, local, path.place
);
if let Place::Base(PlaceBase::Local(user_local)) = path.place {
if let Place {
base: PlaceBase::Local(user_local),
projection: None,
} = path.place {
self.mbcx.used_mut.insert(user_local);
}
}

View file

@ -123,10 +123,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
};
block.and(place)
}
ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static {
ty: expr.ty,
kind: StaticKind::Static(id),
})))),
ExprKind::StaticRef { id } => block.and(Place {
base: PlaceBase::Static(Box::new(Static {
ty: expr.ty,
kind: StaticKind::Static(id),
})),
projection: None,
}),
ExprKind::PlaceTypeAscription { source, user_ty } => {
let place = unpack!(block = this.as_place(block, source));

View file

@ -497,32 +497,48 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let arg_place = unpack!(block = this.as_place(block, arg));
let mutability = match arg_place {
Place::Base(PlaceBase::Local(local)) => this.local_decls[local].mutability,
Place::Projection(box Projection {
base: Place::Base(PlaceBase::Local(local)),
elem: ProjectionElem::Deref,
}) => {
Place {
base: PlaceBase::Local(local),
projection: None,
} => this.local_decls[local].mutability,
Place {
base: PlaceBase::Local(local),
projection: Some(box Projection {
base: None,
elem: ProjectionElem::Deref,
})
} => {
debug_assert!(
this.local_decls[local].is_ref_for_guard(),
"Unexpected capture place",
);
this.local_decls[local].mutability
}
Place::Projection(box Projection {
Place {
ref base,
elem: ProjectionElem::Field(upvar_index, _),
})
| Place::Projection(box Projection {
base:
Place::Projection(box Projection {
ref base,
projection: Some(box Projection {
base: ref base_proj,
elem: 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,
}) => {
elem: ProjectionElem::Deref,
}),
} => {
let place = PlaceRef {
base,
projection: base_proj,
};
// Not projected from the implicit `self` in a closure.
debug_assert!(
match base.local_or_deref_local() {
match place.local_or_deref_local() {
Some(local) => local == Local::new(1),
None => false,
},

View file

@ -296,7 +296,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 let Place::Projection(..) = destination {
if destination.projection.is_some() {
this.local_decls
.push(LocalDecl::new_temp(expr.ty, expr.span));
}

View file

@ -536,7 +536,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let var_ty = self.local_decls[local_id].ty;
let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
self.schedule_drop(span, region_scope, local_id, var_ty, DropKind::Storage);
Place::Base(PlaceBase::Local(local_id))
Place::from(local_id)
}
pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
@ -937,11 +937,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
for Binding { source, .. }
in matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
{
let mut cursor = source;
while let Place::Projection(box Projection { base, elem }) = cursor {
let mut cursor = &source.projection;
while let Some(box Projection { base, elem }) = cursor {
cursor = base;
if let ProjectionElem::Deref = elem {
fake_borrows.insert(cursor.clone());
fake_borrows.insert(Place {
base: source.base.clone(),
projection: cursor.clone(),
});
break;
}
}
@ -1277,7 +1280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
fake_borrows: &'b FxHashSet<Place<'tcx>>,
temp_span: Span,
) -> Vec<(&'b Place<'tcx>, Local)> {
) -> Vec<(PlaceRef<'b, 'tcx>, Local)> {
let tcx = self.hir.tcx();
debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
@ -1287,18 +1290,21 @@ 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;
while let Place::Projection(box Projection { base, elem }) = prefix_cursor {
let mut prefix_cursor = &place.projection;
while let Some(box Projection { base, elem }) = prefix_cursor {
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(base);
all_fake_borrows.push(PlaceRef {
base: &place.base,
projection: base,
});
}
prefix_cursor = base;
}
all_fake_borrows.push(place);
all_fake_borrows.push(place.as_place_ref());
}
// Deduplicate and ensure a deterministic order.
@ -1308,7 +1314,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
all_fake_borrows.into_iter().map(|matched_place| {
let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
let fake_borrow_deref_ty = Place::ty_from(
matched_place.base,
matched_place.projection,
&self.local_decls,
tcx,
)
.ty;
let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
let fake_borrow_temp = self.local_decls.push(
LocalDecl::new_temp(fake_borrow_ty, temp_span)
@ -1339,7 +1351,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
candidate: Candidate<'pat, 'tcx>,
guard: Option<Guard<'tcx>>,
fake_borrows: &Vec<(&Place<'tcx>, Local)>,
fake_borrows: &Vec<(PlaceRef<'_, 'tcx>, Local)>,
scrutinee_span: Span,
region_scope: region::Scope,
) -> BasicBlock {
@ -1470,16 +1482,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let re_erased = tcx.lifetimes.re_erased;
let scrutinee_source_info = self.source_info(scrutinee_span);
for &(place, temp) in fake_borrows {
for (place, temp) in fake_borrows {
let borrow = Rvalue::Ref(
re_erased,
BorrowKind::Shallow,
place.clone(),
Place {
base: place.base.clone(),
projection: place.projection.clone(),
},
);
self.cfg.push_assign(
block,
scrutinee_source_info,
&Place::from(temp),
&Place::from(*temp),
borrow,
);
}
@ -1549,7 +1564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// place they refer to can't be modified by the guard.
for binding in by_value_bindings.clone() {
let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
let place = Place::from(local_id);
let place = Place::from(local_id);
self.cfg.push(
post_guard_block,
Statement {

View file

@ -851,8 +851,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// If constants and statics, we don't generate StorageLive for this
// temporary, so don't try to generate StorageDead for it either.
_ if self.local_scope().is_none() => (),
Operand::Copy(Place::Base(PlaceBase::Local(cond_temp)))
| Operand::Move(Place::Base(PlaceBase::Local(cond_temp))) => {
Operand::Copy(Place {
base: PlaceBase::Local(cond_temp),
projection: None,
})
| Operand::Move(Place {
base: PlaceBase::Local(cond_temp),
projection: None,
}) => {
// Manually drop the condition on both branches.
let top_scope = self.scopes.scopes.last_mut().unwrap();
let top_drop_data = top_scope.drops.pop().unwrap();

View file

@ -14,8 +14,8 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
{
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 {
mir::Place::Projection(ref proj) => {
match move_data.move_paths[child_index].place.projection {
Some(ref proj) => {
if cond(proj) {
return Some(child_index)
}
@ -171,7 +171,7 @@ pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
let move_data = &ctxt.move_data;
for arg in body.args_iter() {
let place = mir::Place::from(arg);
let lookup_result = move_data.rev_lookup.find(&place);
let lookup_result = move_data.rev_lookup.find(place.as_place_ref());
on_lookup_result_bits(tcx, body, move_data,
lookup_result,
|mpi| callback(mpi, DropFlagState::Present));

View file

@ -194,7 +194,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
) {
debug!("kill_borrows_on_place: place={:?}", place);
if let Some(local) = place.base_local() {
if let PlaceBase::Local(local) = place.base {
let other_borrows_of_local = self
.borrow_set
.local_map
@ -205,7 +205,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 let Place::Base(PlaceBase::Local(_)) = place {
if place.projection.is_none() {
trans.kill_all(other_borrows_of_local);
return;
}

View file

@ -309,7 +309,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(self.tcx, self.body, self.move_data(),
self.move_data().rev_lookup.find(dest_place),
self.move_data().rev_lookup.find(dest_place.as_place_ref()),
|mpi| { in_out.insert(mpi); });
}
}
@ -367,7 +367,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 0 (initialized).
on_lookup_result_bits(self.tcx, self.body, self.move_data(),
self.move_data().rev_lookup.find(dest_place),
self.move_data().rev_lookup.find(dest_place.as_place_ref()),
|mpi| { in_out.remove(mpi); });
}
}
@ -423,7 +423,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(self.tcx, self.body, self.move_data(),
self.move_data().rev_lookup.find(dest_place),
self.move_data().rev_lookup.find(dest_place.as_place_ref()),
|mpi| { in_out.insert(mpi); });
}
}

View file

@ -121,11 +121,15 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
StatementKind::StorageDead(l) => sets.kill(l),
StatementKind::Assign(ref place, _)
| StatementKind::SetDiscriminant { ref place, .. } => {
place.base_local().map(|l| sets.gen(l));
if let PlaceBase::Local(local) = place.base {
sets.gen(local);
}
}
StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
for p in &**outputs {
p.base_local().map(|l| sets.gen(l));
if let PlaceBase::Local(local) = p.base {
sets.gen(local);
}
}
}
_ => (),
@ -146,7 +150,9 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
_dest_bb: mir::BasicBlock,
dest_place: &mir::Place<'tcx>,
) {
dest_place.base_local().map(|l| in_out.insert(l));
if let PlaceBase::Local(local) = dest_place.base {
in_out.insert(local);
}
}
}

View file

@ -314,12 +314,12 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> {
fn visit_statement_entry(&mut self,
_loc: Location,
_stmt: &Statement<'tcx>,
_stmt: &'a Statement<'tcx>,
_flow_state: &Self::FlowState) {}
fn visit_terminator_entry(&mut self,
_loc: Location,
_term: &Terminator<'tcx>,
_term: &'a Terminator<'tcx>,
_flow_state: &Self::FlowState) {}
// Main entry point: this drives the processing of results.

View file

@ -106,13 +106,16 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
for proj in place_projection {
let body = self.builder.body;
let tcx = self.builder.tcx;
let place_ty = proj.base.ty(body, tcx).ty;
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::Projection(Box::new(proj.clone())),
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,
@ -159,7 +162,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
&mut self.builder.data.path_map,
&mut self.builder.data.init_path_map,
Some(base),
Place::Projection(Box::new(proj.clone())),
Place {
base: place_base.clone(),
projection: Some(Box::new(proj.clone())),
},
);
ent.insert(path);
path
@ -268,9 +274,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// move-path for the interior so it will be separate from
// the exterior.
self.create_move_path(&place.clone().deref());
self.gather_init(place, InitKind::Shallow);
self.gather_init(place.as_place_ref(), InitKind::Shallow);
} else {
self.gather_init(place, InitKind::Deep);
self.gather_init(place.as_place_ref(), InitKind::Deep);
}
self.gather_rvalue(rval);
}
@ -280,7 +286,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::InlineAsm(ref asm) => {
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
if !kind.is_indirect {
self.gather_init(output, InitKind::Deep);
self.gather_init(output.as_place_ref(), InitKind::Deep);
}
}
for (_, input) in asm.inputs.iter() {
@ -370,7 +376,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
self.create_move_path(location);
self.gather_operand(value);
self.gather_init(location, InitKind::Deep);
self.gather_init(location.as_place_ref(), InitKind::Deep);
}
TerminatorKind::Call {
ref func,
@ -385,7 +391,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
if let Some((ref destination, _bb)) = *destination {
self.create_move_path(destination);
self.gather_init(destination, InitKind::NonPanicPathOnly);
self.gather_init(destination.as_place_ref(), InitKind::NonPanicPathOnly);
}
}
}
@ -420,22 +426,24 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
self.builder.data.loc_map[self.loc].push(move_out);
}
fn gather_init(&mut self, place: &Place<'tcx>, kind: InitKind) {
fn gather_init(&mut self, place: PlaceRef<'cx, 'tcx>, kind: InitKind) {
debug!("gather_init({:?}, {:?})", self.loc, place);
let place = match place {
// Check if we are assigning into a field of a union, if so, lookup the place
// of the union so it is marked as initialized again.
Place::Projection(box Projection {
base,
elem: ProjectionElem::Field(_, _),
}) if match base.ty(self.builder.body, self.builder.tcx).ty.sty {
ty::Adt(def, _) if def.is_union() => true,
_ => false,
} => base,
// Otherwise, lookup the place.
_ => place,
};
let mut place = place;
// Check if we are assigning into a field of a union, if so, lookup the place
// of the union so it is marked as initialized again.
if let Some(box Projection { base: proj_base, elem: ProjectionElem::Field(_, _) }) =
place.projection
{
if let ty::Adt(def, _) =
Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.sty
{
if def.is_union() {
place = PlaceRef { base: place.base, projection: proj_base }
}
}
}
if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) {
let init = self.builder.data.inits.push(Init {

View file

@ -240,8 +240,8 @@ 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: &Place<'tcx>) -> LookupResult {
place.iterate(|place_base, place_projection| {
pub fn find(&self, place_ref: PlaceRef<'cx, 'tcx>) -> 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),
@ -318,7 +318,10 @@ 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)) = path.place { return Some(l); }
if let Place {
base: PlaceBase::Local(l),
projection: None,
} = path.place { return Some(l); }
if let Some(parent) = path.parent { mpi = parent; continue } else { return None }
}
}

View file

@ -455,17 +455,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
mir_place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::Place;
use rustc::mir::PlaceBase;
mir_place.iterate(|place_base, place_projection| {
let mut op = match place_base {
PlaceBase::Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
PlaceBase::Local(local) => {
// FIXME use place_projection.is_empty() when is available
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
let layout = if let Place::Base(_) = mir_place {
// FIXME use place_projection.is_empty() when is available
let layout = if mir_place.projection.is_none() {
layout
} else {
None

View file

@ -15,34 +15,30 @@ pub struct AddRetag;
/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
/// copies. Data races are UB.)
fn is_stable(
place: &Place<'_>,
place: PlaceRef<'_, '_>,
) -> bool {
use rustc::mir::Place::*;
match *place {
// Locals and statics have stable addresses, for sure
Base(PlaceBase::Local { .. }) |
Base(PlaceBase::Static { .. }) =>
true,
// Recurse for projections
Projection(ref proj) => {
match proj.elem {
// Which place this evaluates to can change with any memory write,
// so cannot assume this to be stable.
ProjectionElem::Deref =>
false,
// Array indices are intersting, but MIR building generates a *fresh*
// temporary for every array access, so the index cannot be changed as
// a side-effect.
ProjectionElem::Index { .. } |
// The rest is completely boring, they just offset by a constant.
ProjectionElem::Field { .. } |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } |
ProjectionElem::Downcast { .. } =>
is_stable(&proj.base),
}
if let Some(proj) = &place.projection {
match proj.elem {
// Which place this evaluates to can change with any memory write,
// so cannot assume this to be stable.
ProjectionElem::Deref =>
false,
// Array indices are intersting, but MIR building generates a *fresh*
// temporary for every array access, so the index cannot be changed as
// a side-effect.
ProjectionElem::Index { .. } |
// The rest is completely boring, they just offset by a constant.
ProjectionElem::Field { .. } |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } |
ProjectionElem::Downcast { .. } =>
is_stable(PlaceRef {
base: place.base,
projection: &proj.base,
}),
}
} else {
true
}
}
@ -83,7 +79,8 @@ impl MirPass for AddRetag {
let needs_retag = |place: &Place<'tcx>| {
// FIXME: Instead of giving up for unstable places, we should introduce
// a temporary and retag on that.
is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).ty, tcx)
is_stable(place.as_place_ref())
&& may_have_reference(place.ty(&*local_decls, tcx).ty, tcx)
};
// PART 1

View file

@ -248,8 +248,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
}], &[]);
}
}
let is_borrow_of_interior_mut = context.is_borrow() && !proj.base
.ty(self.body, self.tcx)
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
@ -264,15 +264,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
);
}
let old_source_info = self.source_info;
if let Place::Base(PlaceBase::Local(local)) = proj.base {
if self.body.local_decls[local].internal {
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;
self.source_info = self.body.local_decls[*local].source_info;
}
}
let base_ty = proj.base.ty(self.body, self.tcx).ty;
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",
@ -404,15 +404,16 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
}
fn check_mut_borrowing_layout_constrained_field(
&mut self,
mut place: &Place<'tcx>,
place: &Place<'tcx>,
is_mut_use: bool,
) {
while let &Place::Projection(box Projection {
ref base, ref elem
}) = place {
match *elem {
let mut projection = &place.projection;
while let Some(proj) = projection {
match proj.elem {
ProjectionElem::Field(..) => {
let ty = base.ty(&self.body.local_decls, self.tcx).ty;
let ty =
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) {
(Bound::Unbounded, Bound::Unbounded) => {},
@ -446,7 +447,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
}
_ => {}
}
place = base;
projection = &proj.base;
}
}
}

View file

@ -781,7 +781,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
.ty;
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
if let Place::Base(PlaceBase::Local(local)) = *place {
if let Place {
base: PlaceBase::Local(local),
projection: None,
} = *place {
trace!("checking whether {:?} can be stored to {:?}", value, local);
if self.can_const_prop[local] {
trace!("storing {:?} to {:?}", value, local);
@ -821,11 +824,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
// doesn't use the invalid value
match cond {
Operand::Move(ref place) | Operand::Copy(ref place) => {
let mut place = place;
while let Place::Projection(ref proj) = *place {
place = &proj.base;
}
if let Place::Base(PlaceBase::Local(local)) = *place {
if let PlaceBase::Local(local) = place.base {
self.remove_const(local);
}
},

View file

@ -94,7 +94,10 @@ impl MirPass for CopyPropagation {
// That use of the source must be an assignment.
match statement.kind {
StatementKind::Assign(
Place::Base(PlaceBase::Local(local)),
Place {
base: PlaceBase::Local(local),
projection: None,
},
box Rvalue::Use(ref operand)
) if local == dest_local => {
let maybe_action = match *operand {
@ -145,12 +148,24 @@ 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)),
box Rvalue::Use(Operand::Copy(Place::Base(PlaceBase::Local(src_local)))),
Place {
base: PlaceBase::Local(local),
projection: None,
},
box Rvalue::Use(Operand::Copy(Place {
base: PlaceBase::Local(src_local),
projection: None,
})),
) |
StatementKind::Assign(
Place::Base(PlaceBase::Local(local)),
box Rvalue::Use(Operand::Move(Place::Base(PlaceBase::Local(src_local)))),
Place {
base: PlaceBase::Local(local),
projection: None,
},
box Rvalue::Use(Operand::Move(Place {
base: PlaceBase::Local(src_local),
projection: None,
})),
) if local == dest_local && dest_local == src_local => {}
_ => {
continue;
@ -177,7 +192,10 @@ impl<'tcx> Action<'tcx> {
fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>)
-> Option<Action<'tcx>> {
// The source must be a local.
let src_local = if let Place::Base(PlaceBase::Local(local)) = *src_place {
let src_local = if let Place {
base: PlaceBase::Local(local),
projection: None,
} = *src_place {
local
} else {
debug!(" Can't copy-propagate local: source is not a local");
@ -331,8 +349,14 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
self.super_operand(operand, location);
match *operand {
Operand::Copy(Place::Base(PlaceBase::Local(local))) |
Operand::Move(Place::Base(PlaceBase::Local(local))) if local == self.dest_local => {}
Operand::Copy(Place {
base: PlaceBase::Local(local),
projection: None,
}) |
Operand::Move(Place {
base: PlaceBase::Local(local),
projection: None,
}) if local == self.dest_local => {}
_ => return,
}

View file

@ -105,7 +105,7 @@ fn find_dead_unwinds<'tcx>(
init_data.apply_location(tcx, body, env, loc);
}
let path = match env.move_data.rev_lookup.find(location) {
let path = match env.move_data.rev_lookup.find(location.as_place_ref()) {
LookupResult::Exact(e) => e,
LookupResult::Parent(..) => {
debug!("find_dead_unwinds: has parent; skipping");
@ -360,7 +360,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
statement_index: data.statements.len()
});
let path = self.move_data().rev_lookup.find(location);
let path = self.move_data().rev_lookup.find(location.as_place_ref());
debug!("collect_drop_flags: {:?}, place {:?} ({:?})",
bb, location, path);
@ -399,7 +399,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
match terminator.kind {
TerminatorKind::Drop { ref location, target, unwind } => {
let init_data = self.initialization_data_at(loc);
match self.move_data().rev_lookup.find(location) {
match self.move_data().rev_lookup.find(location.as_place_ref()) {
LookupResult::Exact(path) => {
elaborate_drop(
&mut Elaborator {
@ -488,7 +488,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
is_cleanup: false,
});
match self.move_data().rev_lookup.find(location) {
match self.move_data().rev_lookup.find(location.as_place_ref()) {
LookupResult::Exact(path) => {
debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
let init_data = self.initialization_data_at(loc);
@ -558,7 +558,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
assert!(!self.patch.is_patched(bb));
let loc = Location { block: tgt, statement_index: 0 };
let path = self.move_data().rev_lookup.find(place);
let path = self.move_data().rev_lookup.find(place.as_place_ref());
on_lookup_result_bits(
self.tcx, self.body, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
@ -632,7 +632,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
assert!(!self.patch.is_patched(bb));
let loc = Location { block: bb, statement_index: data.statements.len() };
let path = self.move_data().rev_lookup.find(place);
let path = self.move_data().rev_lookup.find(place.as_place_ref());
on_lookup_result_bits(
self.tcx, self.body, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)

View file

@ -104,11 +104,14 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if place.base_local() == Some(self_arg()) {
replace_base(place, Place::Projection(Box::new(Projection {
base: Place::Base(PlaceBase::Local(self_arg())),
elem: ProjectionElem::Deref,
})));
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,
})),
});
} else {
self.super_place(place, context, location);
}
@ -131,11 +134,14 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if place.base_local() == Some(self_arg()) {
replace_base(place, Place::Projection(Box::new(Projection {
base: Place::Base(PlaceBase::Local(self_arg())),
elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
})));
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),
})),
});
} else {
self.super_place(place, context, location);
}
@ -143,11 +149,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
}
fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
if let Place::Projection(proj) = place {
replace_base(&mut proj.base, new_base);
} else {
*place = new_base;
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;
}
fn self_arg() -> Local {
@ -203,10 +211,13 @@ impl TransformVisitor<'tcx> {
let self_place = Place::from(self_arg());
let base = self_place.downcast_unnamed(variant_index);
let field = Projection {
base: base,
base: base.projection,
elem: ProjectionElem::Field(Field::new(idx), ty),
};
Place::Projection(Box::new(field))
Place {
base: base.base,
projection: Some(Box::new(field)),
}
}
// Create a statement which changes the discriminant
@ -245,7 +256,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location) {
if let Some(l) = place.base_local() {
if let PlaceBase::Local(l) = place.base {
// Replace an Local in the remap with a generator struct access
if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
replace_base(place, self.make_field(variant_index, idx, ty));
@ -835,7 +846,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
&Terminator {
source_info,
kind: TerminatorKind::Drop {
location: Place::Base(PlaceBase::Local(local)),
location: Place {
base: PlaceBase::Local(local),
projection: None,
},
target,
unwind
}

View file

@ -603,7 +603,10 @@ impl Inliner<'tcx> {
// FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries.
if let Operand::Move(Place::Base(PlaceBase::Local(local))) = arg {
if let Operand::Move(Place {
base: PlaceBase::Local(local),
projection: None,
}) = arg {
if caller_body.local_kind(local) == LocalKind::Temp {
// Reuse the operand if it's a temporary already
return local;
@ -671,7 +674,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
_location: Location) {
if *local == RETURN_PLACE {
match self.destination {
Place::Base(PlaceBase::Local(l)) => {
Place {
base: PlaceBase::Local(l),
projection: None,
} => {
*local = l;
return;
},
@ -692,13 +698,20 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
_location: Location) {
match place {
Place::Base(PlaceBase::Local(RETURN_PLACE)) => {
Place {
base: PlaceBase::Local(RETURN_PLACE),
projection: None,
} => {
// Return pointer; update the place itself
*place = self.destination.clone();
},
Place::Base(
PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })
) => {
Place {
base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(promoted),
..
}),
projection: None,
} => {
if let Some(p) = self.promoted_map.get(*promoted).cloned() {
*promoted = p;
}

View file

@ -41,10 +41,14 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
if self.optimizations.and_stars.remove(&location) {
debug!("replacing `&*`: {:?}", rvalue);
let new_place = match *rvalue {
Rvalue::Ref(_, _, Place::Projection(ref mut projection)) => {
Rvalue::Ref(_, _, Place {
ref mut base,
projection: Some(ref mut projection),
}) => Place {
// Replace with dummy
mem::replace(&mut projection.base, Place::Base(PlaceBase::Local(Local::new(0))))
}
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
projection: projection.base.take(),
},
_ => bug!("Detected `&*` but didn't find `&*`!"),
};
*rvalue = Rvalue::Use(Operand::Copy(new_place))
@ -78,9 +82,12 @@ 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::Projection(ref projection)) = *rvalue {
if let Rvalue::Ref(_, _, Place {
ref base,
projection: Some(ref projection),
}) = *rvalue {
if let ProjectionElem::Deref = projection.elem {
if projection.base.ty(self.body, self.tcx).ty.is_region_ptr() {
if Place::ty_from(&base, &projection.base, self.body, self.tcx).ty.is_region_ptr() {
self.optimizations.and_stars.insert(location);
}
}

View file

@ -300,9 +300,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let mut promoted_place = |ty, span| {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
Place::Base(
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(promoted_id), ty })
)
Place {
base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(promoted_id),
ty
}),
projection: None,
}
};
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
match candidate {
@ -310,17 +314,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
match statement.kind {
StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => {
// Find the underlying local for this (necessarily interior) borrow.
let mut place = place;
while let Place::Projection(ref mut proj) = *place {
assert_ne!(proj.elem, ProjectionElem::Deref);
place = &mut proj.base;
};
let ty = place.ty(local_decls, self.tcx).ty;
// Use the underlying local for this (necessarily interior) borrow.
let ty = place.base.ty(local_decls).ty;
let span = statement.source_info.span;
Operand::Move(mem::replace(place, promoted_place(ty, span)))
Operand::Move(Place {
base: mem::replace(&mut place.base, promoted_place(ty, span).base),
projection: None,
})
}
_ => bug!()
}
@ -397,7 +398,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::Base(PlaceBase::Local(local)), _) => {
StatementKind::Assign(Place {
base: PlaceBase::Local(local),
projection: None,
}, _) => {
if temps[local] == TempState::PromotedOut {
// Already promoted.
continue;
@ -444,7 +448,10 @@ pub fn promote_candidates<'tcx>(
for block in body.basic_blocks_mut() {
block.statements.retain(|statement| {
match statement.kind {
StatementKind::Assign(Place::Base(PlaceBase::Local(index)), _) |
StatementKind::Assign(Place {
base: PlaceBase::Local(index),
projection: None,
}, _) |
StatementKind::StorageLive(index) |
StatementKind::StorageDead(index) => {
!promoted(index)
@ -454,7 +461,10 @@ pub fn promote_candidates<'tcx>(
});
let terminator = block.terminator_mut();
match terminator.kind {
TerminatorKind::Drop { location: Place::Base(PlaceBase::Local(index)), target, .. } => {
TerminatorKind::Drop { location: Place {
base: PlaceBase::Local(index),
projection: None,
}, target, .. } => {
if promoted(index) {
terminator.kind = TerminatorKind::Goto {
target,

View file

@ -182,12 +182,16 @@ trait Qualif {
fn in_projection_structurally(
cx: &ConstCx<'_, 'tcx>,
base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>,
) -> bool {
let base_qualif = Self::in_place(cx, &proj.base);
let base_qualif = Self::in_place(cx, PlaceRef {
base,
projection: &proj.base,
});
let qualif = base_qualif && Self::mask_for_ty(
cx,
proj.base.ty(cx.body, cx.tcx)
Place::ty_from(&base, &proj.base, cx.body, cx.tcx)
.projection_ty(cx.tcx, &proj.elem)
.ty,
);
@ -202,26 +206,44 @@ trait Qualif {
}
}
fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool {
Self::in_projection_structurally(cx, proj)
fn in_projection(
cx: &ConstCx<'_, 'tcx>,
base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>,
) -> bool {
Self::in_projection_structurally(cx, base, proj)
}
fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool {
match *place {
Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
Place::Base(PlaceBase::Static(box Static {kind: StaticKind::Promoted(_), .. })) =>
bug!("qualifying already promoted MIR"),
Place::Base(PlaceBase::Static(ref static_)) => {
fn in_place(cx: &ConstCx<'_, 'tcx>, place: PlaceRef<'_, 'tcx>) -> bool {
match place {
PlaceRef {
base: PlaceBase::Local(local),
projection: None,
} => Self::in_local(cx, *local),
PlaceRef {
base: PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}),
projection: None,
} => bug!("qualifying already promoted MIR"),
PlaceRef {
base: PlaceBase::Static(static_),
projection: None,
} => {
Self::in_static(cx, static_)
},
Place::Projection(ref proj) => Self::in_projection(cx, proj),
PlaceRef {
base,
projection: Some(proj),
} => Self::in_projection(cx, base, proj),
}
}
fn in_operand(cx: &ConstCx<'_, 'tcx>, operand: &Operand<'tcx>) -> bool {
match *operand {
Operand::Copy(ref place) |
Operand::Move(ref place) => Self::in_place(cx, place),
Operand::Move(ref place) => Self::in_place(cx, place.as_place_ref()),
Operand::Constant(ref constant) => {
if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
@ -250,7 +272,7 @@ trait Qualif {
Rvalue::NullaryOp(..) => false,
Rvalue::Discriminant(ref place) |
Rvalue::Len(ref place) => Self::in_place(cx, place),
Rvalue::Len(ref place) => Self::in_place(cx, place.as_place_ref()),
Rvalue::Use(ref operand) |
Rvalue::Repeat(ref operand, _) |
@ -264,16 +286,19 @@ trait Qualif {
Rvalue::Ref(_, _, ref place) => {
// Special-case reborrows to be more like a copy of the reference.
if let Place::Projection(ref proj) = *place {
if let Some(ref proj) = place.projection {
if let ProjectionElem::Deref = proj.elem {
let base_ty = proj.base.ty(cx.body, cx.tcx).ty;
let base_ty = Place::ty_from(&place.base, &proj.base, cx.body, cx.tcx).ty;
if let ty::Ref(..) = base_ty.sty {
return Self::in_place(cx, &proj.base);
return Self::in_place(cx, PlaceRef {
base: &place.base,
projection: &proj.base,
});
}
}
}
Self::in_place(cx, place)
Self::in_place(cx, place.as_place_ref())
}
Rvalue::Aggregate(_, ref operands) => {
@ -421,7 +446,11 @@ impl Qualif for IsNotPromotable {
}
}
fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool {
fn in_projection(
cx: &ConstCx<'_, 'tcx>,
base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>,
) -> bool {
match proj.elem {
ProjectionElem::Deref |
ProjectionElem::Downcast(..) => return true,
@ -432,7 +461,7 @@ impl Qualif for IsNotPromotable {
ProjectionElem::Field(..) => {
if cx.mode == Mode::NonConstFn {
let base_ty = proj.base.ty(cx.body, cx.tcx).ty;
let base_ty = Place::ty_from(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() {
@ -443,7 +472,7 @@ impl Qualif for IsNotPromotable {
}
}
Self::in_projection_structurally(cx, proj)
Self::in_projection_structurally(cx, base, proj)
}
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
@ -773,20 +802,24 @@ 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 = place;
while let Place::Projection(ref proj) = *place {
let mut place_projection = &place.projection;
while let Some(proj) = place_projection {
if proj.elem == ProjectionElem::Deref {
break;
}
place = &proj.base;
place_projection = &proj.base;
}
debug!("qualify_consts: promotion candidate: place={:?}", place);
debug!(
"qualify_consts: promotion candidate: place={:?} {:?}",
place.base, place_projection
);
// 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 Place::Base(PlaceBase::Local(local)) = *place {
if self.body.local_kind(local) == LocalKind::Temp {
if let (PlaceBase::Local(local), None) = (&place.base, place_projection) {
if self.body.local_kind(*local) == LocalKind::Temp {
debug!("qualify_consts: promotion candidate: local={:?}", local);
// The borrowed place doesn't have `HasMutInterior`
// (from `in_rvalue`), so we can safely ignore
@ -794,7 +827,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
// This allows borrowing fields which don't have
// `HasMutInterior`, from a type that does, e.g.:
// `let _: &'static _ = &(Cell::new(1), 2).1;`
let mut local_qualifs = self.qualifs_in_local(local);
let mut local_qualifs = self.qualifs_in_local(*local);
// Any qualifications, except HasMutInterior (see above), disqualify
// from promotion.
// This is, in particular, the "implicit promotion" version of
@ -821,34 +854,31 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
_ => {},
}
let mut dest = dest;
let mut dest_projection = &dest.projection;
let index = loop {
match dest {
match (&dest.base, dest_projection) {
// We treat all locals equal in constants
Place::Base(PlaceBase::Local(index)) => break *index,
(&PlaceBase::Local(index), None) => break index,
// projections are transparent for assignments
// we qualify the entire destination at once, even if just a field would have
// stricter qualification
Place::Projection(proj) => {
(base, Some(proj)) => {
// Catch more errors in the destination. `visit_place` also checks various
// projection rules like union field access and raw pointer deref
self.visit_place(
dest,
PlaceContext::MutatingUse(MutatingUseContext::Store),
location
);
dest = &proj.base;
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
self.visit_place_base(base, context, location);
self.visit_projection(base, proj, context, location);
dest_projection = &proj.base;
},
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
bug!("promoteds don't exist yet during promotion"),
Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
(&PlaceBase::Static(box Static {
kind: StaticKind::Promoted(_),
..
}), None) => bug!("promoteds don't exist yet during promotion"),
(&PlaceBase::Static(box Static{ kind: _, .. }), None) => {
// 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
self.visit_place(
dest,
PlaceContext::MutatingUse(MutatingUseContext::Store),
location
);
let context = PlaceContext::MutatingUse(MutatingUseContext::Store);
self.visit_place_base(&dest.base, context, location);
return;
}
}
@ -950,7 +980,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
match *candidate {
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign(_, box Rvalue::Repeat(
Operand::Move(Place::Base(PlaceBase::Local(index))),
Operand::Move(Place {
base: PlaceBase::Local(index),
projection: None,
}),
_
)) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index);
@ -959,7 +992,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign(
_,
box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
box Rvalue::Ref(_, _, Place {
base: PlaceBase::Local(index),
projection: None,
})
) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index);
}
@ -1043,6 +1079,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
fn visit_projection(
&mut self,
place_base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>,
context: PlaceContext,
location: Location,
@ -1051,14 +1088,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
"visit_place_projection: proj={:?} context={:?} location={:?}",
proj, context, location,
);
self.super_projection(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 = proj.base.ty(self.body, self.tcx).ty;
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
match self.mode {
Mode::NonConstFn => {},
_ => {
@ -1082,7 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
ProjectionElem::Subslice {..} |
ProjectionElem::Field(..) |
ProjectionElem::Index(_) => {
let base_ty = proj.base.ty(self.body, self.tcx).ty;
let base_ty = Place::ty_from(place_base, &proj.base, self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
if def.is_union() {
match self.mode {
@ -1119,7 +1156,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
match *operand {
Operand::Move(ref place) => {
// Mark the consumed locals to indicate later drops are noops.
if let Place::Base(PlaceBase::Local(local)) = *place {
if let Place {
base: PlaceBase::Local(local),
projection: None,
} = *place {
self.cx.per_local[NeedsDrop].remove(local);
}
}
@ -1135,16 +1175,16 @@ 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 Place::Projection(ref proj) = *place {
if let Some(ref proj) = place.projection {
if let ProjectionElem::Deref = proj.elem {
let base_ty = proj.base.ty(self.body, self.tcx).ty;
let base_ty = Place::ty_from(&place.base, &proj.base, self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.sty {
reborrow_place = Some(&proj.base);
}
}
}
if let Some(place) = reborrow_place {
if let Some(proj) = reborrow_place {
let ctx = match kind {
BorrowKind::Shared => PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow,
@ -1159,7 +1199,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
MutatingUseContext::Borrow,
),
};
self.visit_place(place, ctx, location);
self.visit_place_base(&place.base, ctx, location);
if let Some(proj) = proj {
self.visit_projection(&place.base, proj, ctx, location);
}
} else {
self.super_rvalue(rvalue, location);
}
@ -1428,7 +1471,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
unleash_miri!(self);
// HACK(eddyb): emulate a bit of dataflow analysis,
// conservatively, that drop elaboration will do.
let needs_drop = if let Place::Base(PlaceBase::Local(local)) = *place {
let needs_drop = if let Place {
base: PlaceBase::Local(local),
projection: None,
} = *place {
if NeedsDrop::in_local(self, local) {
Some(self.body.local_decls[local].source_info.span)
} else {
@ -1658,7 +1704,10 @@ impl MirPass for QualifyAndPromoteConstants {
let terminator = block.terminator_mut();
match terminator.kind {
TerminatorKind::Drop {
location: Place::Base(PlaceBase::Local(index)),
location: Place {
base: PlaceBase::Local(index),
projection: None,
},
target,
..
} => {

View file

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

View file

@ -118,8 +118,14 @@ fn each_block<'tcx, O>(
};
assert!(args.len() == 1);
let peek_arg_place = match args[0] {
mir::Operand::Copy(ref place @ mir::Place::Base(mir::PlaceBase::Local(_))) |
mir::Operand::Move(ref place @ mir::Place::Base(mir::PlaceBase::Local(_))) => Some(place),
mir::Operand::Copy(ref place @ mir::Place {
base: mir::PlaceBase::Local(_),
projection: None,
}) |
mir::Operand::Move(ref place @ mir::Place {
base: mir::PlaceBase::Local(_),
projection: None,
}) => Some(place),
_ => None,
};
@ -162,7 +168,7 @@ fn each_block<'tcx, O>(
if place == peek_arg_place {
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) {
match move_data.rev_lookup.find(peeking_at_place.as_place_ref()) {
LookupResult::Exact(peek_mpi) => {
let bit_state = on_entry.contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
@ -186,7 +192,7 @@ fn each_block<'tcx, O>(
}
}
let lhs_mpi = move_data.rev_lookup.find(place);
let lhs_mpi = move_data.rev_lookup.find(place.as_place_ref());
debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}",
place, lhs_mpi, stmt);

View file

@ -59,19 +59,27 @@ 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 Place::Projection(ref proj) = *src_place {
if let Some(ref proj) = src_place.projection {
if let ProjectionElem::ConstantIndex{offset: _,
min_length: _,
from_end: false} = proj.elem {
// no need to transformation
} else {
let place_ty = proj.base.ty(self.body, self.tcx).ty;
let place_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.assert_usize(self.tcx) {
assert!(size <= u32::max_value() as u64,
"uniform array move out doesn't supported
for array bigger then u32");
self.uniform(location, dst_place, proj, item_ty, size as u32);
self.uniform(
location,
dst_place,
&src_place.base,
proj,
item_ty,
size as u32,
);
}
}
@ -86,6 +94,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
fn uniform(&mut self,
location: Location,
dst_place: &Place<'tcx>,
base: &PlaceBase<'tcx>,
proj: &Projection<'tcx>,
item_ty: &'tcx ty::TyS<'tcx>,
size: u32) {
@ -100,13 +109,20 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
Place::from(temp),
Rvalue::Use(
Operand::Move(
Place::Projection(box Projection{
base: proj.base.clone(),
elem: ProjectionElem::ConstantIndex{
offset: i,
min_length: size,
from_end: false}
}))));
Place {
base: base.clone(),
projection: Some(box Projection {
base: proj.base.clone(),
elem: ProjectionElem::ConstantIndex {
offset: i,
min_length: size,
from_end: false,
}
}),
}
)
)
);
temp
}).collect();
self.patch.add_assign(
@ -130,12 +146,20 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
dst_place.clone(),
Rvalue::Use(
Operand::Move(
Place::Projection(box Projection{
base: proj.base.clone(),
elem: ProjectionElem::ConstantIndex{
offset: size - offset,
min_length: size,
from_end: false }}))));
Place {
base: base.clone(),
projection: Some(box Projection {
base: proj.base.clone(),
elem: ProjectionElem::ConstantIndex {
offset: size - offset,
min_length: size,
from_end: false,
},
}),
}
)
)
);
}
_ => {}
}
@ -173,7 +197,10 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
if let StatementKind::Assign(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))) = item {
if let Operand::Move(Place {
base: PlaceBase::Local(local),
projection: None,
}) = item {
let local_use = &visitor.locals_use[*local];
let opt_index_and_place =
Self::try_get_item_source(local_use, body);
@ -189,7 +216,8 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
let opt_size = opt_src_place.and_then(|src_place| {
let src_ty = src_place.ty(body, tcx).ty;
let src_ty =
Place::ty_from(src_place.base, src_place.projection, body, tcx).ty;
if let ty::Array(_, ref size_o) = src_ty.sty {
size_o.assert_usize(tcx)
} else {
@ -210,7 +238,7 @@ impl RestoreSubsliceArrayMoveOut {
// indices is an integer interval. If all checks pass do the replacent.
// items are Vec<Option<LocalUse, index in source array, source place for init local>>
fn check_and_patch<'tcx>(candidate: Location,
items: &[Option<(&LocalUse, u32, &Place<'tcx>)>],
items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
opt_size: Option<u64>,
patch: &mut MirPatch<'tcx>,
dst_place: &Place<'tcx>) {
@ -218,6 +246,7 @@ impl RestoreSubsliceArrayMoveOut {
if opt_size.is_some() && items.iter().all(
|l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
let src_place = opt_src_place.unwrap();
let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
for i in 1..indices.len() {
@ -241,25 +270,39 @@ impl RestoreSubsliceArrayMoveOut {
dst_place.clone(),
Rvalue::Use(
Operand::Move(
Place::Projection(box Projection{
base: opt_src_place.unwrap().clone(),
elem: ProjectionElem::Subslice{
from: min, to: size - max - 1}}))));
Place {
base: src_place.base.clone(),
projection: Some(box Projection {
base: src_place.projection.clone(),
elem: ProjectionElem::Subslice{
from: min, to: size - max - 1}})})));
}
}
fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
body: &'a Body<'tcx>) -> Option<(u32, &'a Place<'tcx>)> {
body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
if let Some(location) = local_use.first_use {
let block = &body[location.block];
if block.statements.len() > location.statement_index {
let statement = &block.statements[location.statement_index];
if let StatementKind::Assign(
Place::Base(PlaceBase::Local(_)),
box Rvalue::Use(Operand::Move(Place::Projection(box Projection{
ref base, elem: ProjectionElem::ConstantIndex{
offset, min_length: _, from_end: false}})))) = statement.kind {
return Some((offset, base))
Place {
base: PlaceBase::Local(_),
projection: None,
},
box Rvalue::Use(Operand::Move(Place {
base,
projection: Some(box Projection {
base: proj_base,
elem: ProjectionElem::ConstantIndex {
offset, min_length: _, from_end: false
}
}),
}))) = &statement.kind {
return Some((*offset, PlaceRef {
base,
projection: proj_base,
}))
}
}
}

View file

@ -38,15 +38,14 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
where
L: HasLocalDecls<'tcx>,
{
let mut place = place;
while let &Place::Projection(box Projection {
ref base, ref elem
}) = place {
match *elem {
let mut place_projection = &place.projection;
while let Some(proj) = place_projection {
match proj.elem {
// encountered a Deref, which is ABI-aligned
ProjectionElem::Deref => break,
ProjectionElem::Field(..) => {
let ty = base.ty(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
@ -56,7 +55,7 @@ where
}
_ => {}
}
place = base;
place_projection = &proj.base;
}
false

View file

@ -584,10 +584,13 @@ where
(Rvalue::Ref(
tcx.lifetimes.re_erased,
BorrowKind::Mut { allow_two_phase_borrow: false },
Place::Projection(Box::new(Projection {
base: Place::Base(PlaceBase::Local(cur)),
elem: ProjectionElem::Deref,
}))
Place {
base: PlaceBase::Local(cur),
projection: Some(Box::new(Projection {
base: None,
elem: ProjectionElem::Deref,
})),
}
),
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
} else {