Migrate from Place enum to Place struct
This commit is contained in:
parent
5c26b52368
commit
d0accade3e
46 changed files with 1457 additions and 786 deletions
|
@ -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>,
|
||||
}
|
||||
|
||||
|
@ -1827,7 +1827,10 @@ newtype_index! {
|
|||
}
|
||||
|
||||
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 +1856,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 +1868,70 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Local> for Place<'_> {
|
||||
fn from(local: Local) -> Self {
|
||||
Place::Base(local.into())
|
||||
Place {
|
||||
base: local.into(),
|
||||
projection: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3155,18 +3177,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 => {
|
||||
}
|
||||
|
|
|
@ -103,7 +103,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);
|
||||
|
@ -157,7 +160,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
debug!("visit_place(place={:?}, context={:?})", place, context);
|
||||
let cx = self.fx.cx;
|
||||
|
||||
if let mir::Place::Projection(ref proj) = *place {
|
||||
if let Some(proj) = &place.projection {
|
||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||
let is_consume = match context {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
|
@ -165,7 +168,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
_ => false
|
||||
};
|
||||
if is_consume {
|
||||
let base_ty = proj.base.ty(self.fx.mir, cx.tcx());
|
||||
let base_ty = mir::Place::ty_from(&place.base, &proj.base, self.fx.mir, cx.tcx());
|
||||
let base_ty = self.fx.monomorphize(&base_ty);
|
||||
|
||||
// ZSTs don't require any actual memory access.
|
||||
|
@ -183,7 +186,15 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
// 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);
|
||||
self.visit_place(
|
||||
// FIXME do not clone
|
||||
&mir::Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
context,
|
||||
location,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +203,11 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
// A deref projection only reads the pointer, never needs the place.
|
||||
if let mir::ProjectionElem::Deref = proj.elem {
|
||||
return self.visit_place(
|
||||
&proj.base,
|
||||
// FIXME do not clone
|
||||
&mir::Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
);
|
||||
|
|
|
@ -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"),
|
||||
|
@ -1153,7 +1160,10 @@ 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"),
|
||||
|
|
|
@ -435,9 +435,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
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 {
|
||||
mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: None,
|
||||
} => {
|
||||
match self.locals[*index] {
|
||||
LocalRef::Place(place) => {
|
||||
return place;
|
||||
}
|
||||
|
@ -449,15 +452,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
mir::Place::Base(
|
||||
mir::PlaceBase::Static(
|
||||
box mir::Static { ty, kind: mir::StaticKind::Promoted(promoted) }
|
||||
)
|
||||
) => {
|
||||
mir::Place {
|
||||
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 +485,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::Place {
|
||||
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::Place {
|
||||
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::Place {
|
||||
base: base.clone(),
|
||||
projection: proj_base.clone(),
|
||||
}).deref(bx.cx())
|
||||
}
|
||||
mir::Place::Projection(ref projection) => {
|
||||
let cg_base = self.codegen_place(bx, &projection.base);
|
||||
mir::Place {
|
||||
base,
|
||||
projection: Some(projection),
|
||||
} => {
|
||||
// FIXME turn this recursion into iteration
|
||||
let cg_base = self.codegen_place(bx, &mir::Place {
|
||||
base: base.clone(),
|
||||
projection: projection.base.clone(),
|
||||
});
|
||||
|
||||
match projection.elem {
|
||||
mir::ProjectionElem::Deref => bug!(),
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -72,9 +72,15 @@ 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.base, &used_place.projection, PrefixSet::All)
|
||||
.last()
|
||||
.unwrap();
|
||||
|
||||
if self.uninitialized_error_reported.contains(root_place) {
|
||||
if self.uninitialized_error_reported.contains(&Place {
|
||||
base: root_place.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
}) {
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
|
||||
root_place
|
||||
|
@ -82,7 +88,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.uninitialized_error_reported.insert(root_place.clone());
|
||||
self.uninitialized_error_reported.insert(Place {
|
||||
base: root_place.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
});
|
||||
|
||||
let item_msg = match self.describe_place_with_options(used_place,
|
||||
IncludingDowncast(true)) {
|
||||
|
@ -105,8 +114,8 @@ 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)
|
||||
.any(|p| p == used_place)
|
||||
if self.prefixes(&reported_place.base, &reported_place.projection, PrefixSet::All)
|
||||
.any(|p| *p.0 == used_place.base && *p.1 == used_place.projection)
|
||||
{
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error suppressed \
|
||||
|
@ -232,7 +241,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 {
|
||||
|
@ -575,8 +587,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 +607,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((Place {
|
||||
base: base.clone(),
|
||||
projection: base_proj.clone(),
|
||||
}, field));
|
||||
},
|
||||
_ => current = base,
|
||||
_ => current = base_proj,
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -609,13 +630,27 @@ 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(&Place {
|
||||
base: base.clone(),
|
||||
projection: proj_base.clone(),
|
||||
}).unwrap_or_else(|| "_".to_owned());
|
||||
|
||||
return Some((
|
||||
describe_place(base),
|
||||
describe_base_place,
|
||||
describe_place(first_borrowed_place),
|
||||
describe_place(second_borrowed_place),
|
||||
union_ty.to_string(),
|
||||
|
@ -624,7 +659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
current = base;
|
||||
current = proj_base;
|
||||
}
|
||||
None
|
||||
})
|
||||
|
@ -663,20 +698,26 @@ 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.base,
|
||||
&borrow.borrowed_place.projection,
|
||||
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.1.is_none());
|
||||
let proper_span = match root_place.0 {
|
||||
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.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
}, borrow_span))
|
||||
{
|
||||
debug!(
|
||||
"suppressing access_place error when borrow doesn't live long enough for {:?}",
|
||||
|
@ -686,7 +727,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
self.access_place_error_reported
|
||||
.insert((root_place.clone(), borrow_span));
|
||||
.insert((Place {
|
||||
base: root_place.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
}, borrow_span));
|
||||
|
||||
if let StorageDeadOrDrop::Destructor(dropped_ty) =
|
||||
self.classify_drop_access_kind(&borrow.borrowed_place)
|
||||
|
@ -709,7 +753,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
|
||||
|
||||
let err = match (place_desc, explanation) {
|
||||
(Some(_), _) if self.is_place_thread_local(root_place) => {
|
||||
(Some(_), _) if self.is_place_thread_local(&Place {
|
||||
base: root_place.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
}) => {
|
||||
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
|
||||
}
|
||||
// If the outlives constraint comes from inside the closure,
|
||||
|
@ -1061,7 +1108,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 +1133,17 @@ 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.base,
|
||||
&borrow.borrowed_place.projection,
|
||||
PrefixSet::All)
|
||||
.last()
|
||||
.unwrap();
|
||||
let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
|
||||
let local = if let (PlaceBase::Local(local), 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(),
|
||||
|
@ -1385,7 +1437,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 {
|
||||
|
@ -1456,19 +1511,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
fn classify_drop_access_kind(&self, place: &Place<'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(&Place {
|
||||
base: place.base.clone(),
|
||||
projection: base.clone(),
|
||||
});
|
||||
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 +1533,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 +1600,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 +1616,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 +1744,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
|
||||
|
|
|
@ -150,16 +150,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
including_downcast: &IncludingDowncast,
|
||||
) -> Result<(), ()> {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(local)) => {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
} => {
|
||||
self.append_local_to_string(local, buf)?;
|
||||
}
|
||||
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
|
||||
Place {
|
||||
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), .. })) => {
|
||||
Place {
|
||||
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) => {
|
||||
Place {
|
||||
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,
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
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(
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
)?;
|
||||
} else {
|
||||
// FIXME deduplicate this and the _ => body below
|
||||
buf.push_str(&"*");
|
||||
self.append_place_to_string(
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
buf.push_str(&"*");
|
||||
self.append_place_to_string(
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProjectionElem::Downcast(..) => {
|
||||
self.append_place_to_string(
|
||||
&proj.base,
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
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(&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
}, field);
|
||||
self.append_place_to_string(
|
||||
&proj.base,
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
|
@ -243,7 +292,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
autoderef = true;
|
||||
|
||||
self.append_place_to_string(
|
||||
&proj.base,
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
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,
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
},
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
|
@ -288,18 +343,31 @@ 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: &Place<'tcx>, field: Field) -> String {
|
||||
// FIXME Place2 Make this work iteratively
|
||||
match place {
|
||||
Place {
|
||||
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_)) =>
|
||||
Place {
|
||||
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),
|
||||
Place {
|
||||
base,
|
||||
projection: Some(proj),
|
||||
} => match proj.elem {
|
||||
ProjectionElem::Deref => self.describe_field(&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
}, field),
|
||||
ProjectionElem::Downcast(_, variant_index) => {
|
||||
let base_ty = base.ty(self.body, self.infcx.tcx).ty;
|
||||
let base_ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
self.describe_field_from_ty(&base_ty, field, Some(variant_index))
|
||||
}
|
||||
ProjectionElem::Field(_, field_type) => {
|
||||
|
@ -308,7 +376,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {
|
||||
self.describe_field(&proj.base, field)
|
||||
self.describe_field(&Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
}, field)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -366,9 +437,13 @@ 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 {
|
||||
if let Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Static(def_id),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
} = place {
|
||||
let attrs = self.infcx.tcx.get_attrs(*def_id);
|
||||
let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
|
||||
|
||||
|
@ -750,7 +825,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),
|
||||
|
|
|
@ -890,7 +890,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,
|
||||
}
|
||||
|
||||
|
@ -1166,12 +1167,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,
|
||||
);
|
||||
|
@ -1305,16 +1309,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) {
|
||||
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 +1322,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;
|
||||
|
@ -1434,30 +1438,39 @@ 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.base, &place.projection, 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.1.is_none());
|
||||
let (might_be_alive, will_be_dropped) = match root_place.0 {
|
||||
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(&Place {
|
||||
base: root_place.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
}))
|
||||
}
|
||||
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 {
|
||||
|
@ -1475,7 +1488,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.body,
|
||||
place,
|
||||
borrow.kind,
|
||||
root_place,
|
||||
&Place {
|
||||
base: root_place.0.clone(),
|
||||
projection: root_place.1.clone(),
|
||||
},
|
||||
sd,
|
||||
places_conflict::PlaceConflictBias::Overlap,
|
||||
) {
|
||||
|
@ -1610,7 +1626,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.report_use_of_moved_or_uninitialized(
|
||||
location,
|
||||
desired_action,
|
||||
(prefix, place_span.0, place_span.1),
|
||||
(&prefix, place_span.0, place_span.1),
|
||||
mpi,
|
||||
);
|
||||
return; // don't bother finding other problems.
|
||||
|
@ -1689,18 +1705,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
fn move_path_closest_to<'a>(
|
||||
&mut self,
|
||||
place: &'a Place<'tcx>,
|
||||
) -> Result<(&'a Place<'tcx>, MovePathIndex), NoMovePathFound> where 'cx: 'a {
|
||||
let mut last_prefix = place;
|
||||
for prefix in self.prefixes(place, PrefixSet::All) {
|
||||
if let Some(mpi) = self.move_path_for_place(prefix) {
|
||||
return Ok((prefix, mpi));
|
||||
) -> Result<(Place<'tcx>, MovePathIndex), NoMovePathFound> where 'cx: 'a {
|
||||
let mut last_prefix = &place.base;
|
||||
|
||||
for prefix in self.prefixes(&place.base, &place.projection, PrefixSet::All) {
|
||||
if let Some(mpi) = self.move_path_for_place(&Place {
|
||||
base: prefix.0.clone(),
|
||||
projection: prefix.1.clone(),
|
||||
}) {
|
||||
return Ok((Place {
|
||||
base: prefix.0.clone(),
|
||||
projection: prefix.1.clone(),
|
||||
}, mpi));
|
||||
}
|
||||
last_prefix = prefix;
|
||||
|
||||
last_prefix = prefix.0;
|
||||
}
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1723,83 +1747,86 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'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,
|
||||
(&Place {
|
||||
base: place.base.clone(),
|
||||
projection: base.clone(),
|
||||
}, 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,
|
||||
(&Place {
|
||||
base: place.base.clone(),
|
||||
projection: base.clone(),
|
||||
}, 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, &Place {
|
||||
base: place.base.clone(),
|
||||
projection: base.clone(),
|
||||
}, 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>(
|
||||
|
@ -1845,8 +1872,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// Find the shortest uninitialized prefix you can reach
|
||||
// without going over a Deref.
|
||||
let mut shortest_uninit_seen = None;
|
||||
for prefix in this.prefixes(base, PrefixSet::Shallow) {
|
||||
let mpi = match this.move_path_for_place(prefix) {
|
||||
for prefix in this.prefixes(&base.base, &base.projection, PrefixSet::Shallow) {
|
||||
let mpi = match this.move_path_for_place(&Place {
|
||||
base: prefix.0.clone(),
|
||||
projection: prefix.1.clone(),
|
||||
}) {
|
||||
Some(mpi) => mpi, None => continue,
|
||||
};
|
||||
|
||||
|
@ -1881,7 +1911,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
this.report_use_of_moved_or_uninitialized(
|
||||
location,
|
||||
InitializationRequiringAction::PartialAssignment,
|
||||
(prefix, base, span),
|
||||
(&Place {
|
||||
base: prefix.0.clone(),
|
||||
projection: prefix.1.clone(),
|
||||
}, base, span),
|
||||
mpi,
|
||||
);
|
||||
}
|
||||
|
@ -1911,7 +1944,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 +1960,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 +1972,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 +1993,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 +2014,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.report_mutability_error(
|
||||
place,
|
||||
span,
|
||||
_place_err,
|
||||
&Place {
|
||||
base: _place_err.0.clone(),
|
||||
projection: _place_err.1.clone(),
|
||||
},
|
||||
error_access,
|
||||
location,
|
||||
);
|
||||
|
@ -2015,7 +2051,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.report_mutability_error(
|
||||
place,
|
||||
span,
|
||||
the_place_err,
|
||||
&Place {
|
||||
base: the_place_err.0.clone(),
|
||||
projection: the_place_err.1.clone(),
|
||||
},
|
||||
error_access,
|
||||
location,
|
||||
);
|
||||
|
@ -2044,7 +2083,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 +2097,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: Some(proj),
|
||||
is_local_mutation_allowed: _,
|
||||
} => {
|
||||
if let Some(field) = self.is_upvar_field_projection(place) {
|
||||
if let Some(field) = self.is_upvar_field_projection(&Place {
|
||||
base: place_base.clone(),
|
||||
projection: Some(proj.clone()),
|
||||
}) {
|
||||
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 +2125,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(&Place {
|
||||
base: place_base.clone(),
|
||||
projection: place_projection.clone(),
|
||||
}) {
|
||||
Some(field)
|
||||
if self.upvars[field.index()].by_ref =>
|
||||
{
|
||||
|
@ -2143,19 +2205,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 +2226,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 +2239,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(&Place {
|
||||
base: place_base.clone(),
|
||||
projection: place_projection.clone(),
|
||||
});
|
||||
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 +2283,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2237,32 +2307,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
/// 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)
|
||||
};
|
||||
let mut place_projection = place.projection.clone();
|
||||
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.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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -273,21 +276,22 @@ 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 {
|
||||
let description = if place.projection.is_none() {
|
||||
format!("static item `{}`", self.describe_place(place).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 = Place {
|
||||
base: place.base.clone(),
|
||||
projection: base_static.clone(),
|
||||
};
|
||||
|
||||
format!(
|
||||
"`{:?}` as `{:?}` is a static item",
|
||||
self.describe_place(place).unwrap(),
|
||||
self.describe_place(base_static).unwrap(),
|
||||
self.describe_place(&base_static).unwrap(),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -304,15 +308,24 @@ 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)
|
||||
.find_map(|p| self.is_upvar_field_projection(p));
|
||||
let upvar_field = self.prefixes(&move_place.base, &move_place.projection, PrefixSet::All)
|
||||
.find_map(|p| self.is_upvar_field_projection(&Place {
|
||||
base: p.0.clone(),
|
||||
projection: p.1.clone(),
|
||||
}));
|
||||
|
||||
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 }) => Place {
|
||||
base: deref_target_place.base.clone(),
|
||||
projection: base.clone(),
|
||||
},
|
||||
_ => bug!("deref_target_place is not a deref projection"),
|
||||
};
|
||||
|
||||
if let Place::Base(PlaceBase::Local(local)) = *deref_base {
|
||||
if let Place {
|
||||
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(
|
||||
|
@ -378,7 +391,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
diag
|
||||
}
|
||||
_ => {
|
||||
let source = self.borrowed_content_source(deref_base);
|
||||
let source = self.borrowed_content_source(&deref_base);
|
||||
match (self.describe_place(move_place), source.describe_for_named_place()) {
|
||||
(Some(place_desc), Some(source_desc)) => {
|
||||
self.cannot_move_out_of(
|
||||
|
|
|
@ -44,9 +44,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
|
||||
|
||||
match the_place_err {
|
||||
Place::Base(PlaceBase::Local(local)) => {
|
||||
Place {
|
||||
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,12 +62,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Place::Projection(box Projection {
|
||||
base,
|
||||
elem: ProjectionElem::Field(upvar_index, _),
|
||||
}) => {
|
||||
Place {
|
||||
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());
|
||||
|
@ -73,11 +83,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Place::Projection(box Projection {
|
||||
base,
|
||||
elem: ProjectionElem::Deref,
|
||||
}) => {
|
||||
if *base == Place::Base(PlaceBase::Local(Local::new(1))) &&
|
||||
Place {
|
||||
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());
|
||||
|
@ -91,8 +106,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
", 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 +115,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(&Place {
|
||||
base: the_place_err.base.clone(),
|
||||
projection: base.clone(),
|
||||
});
|
||||
let pointer_type = source.describe_for_immutable_place();
|
||||
opt_source = Some(source);
|
||||
if let Some(desc) = access_place_desc {
|
||||
|
@ -119,11 +137,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) =>
|
||||
unreachable!(),
|
||||
Place {
|
||||
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 {
|
||||
Place {
|
||||
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 +167,36 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Place::Projection(box Projection {
|
||||
Place {
|
||||
base: _,
|
||||
elem: ProjectionElem::Index(_),
|
||||
})
|
||||
| Place::Projection(box Projection {
|
||||
projection:
|
||||
Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Index(_),
|
||||
}),
|
||||
}
|
||||
| Place {
|
||||
base: _,
|
||||
elem: ProjectionElem::ConstantIndex { .. },
|
||||
})
|
||||
| Place::Projection(box Projection {
|
||||
projection:
|
||||
Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::ConstantIndex { .. },
|
||||
}),
|
||||
}
|
||||
| Place {
|
||||
base: _,
|
||||
elem: ProjectionElem::Subslice { .. },
|
||||
})
|
||||
| Place::Projection(box Projection {
|
||||
projection: Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Subslice { .. },
|
||||
}),
|
||||
}
|
||||
| Place {
|
||||
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);
|
||||
|
@ -203,21 +251,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,
|
||||
Place {
|
||||
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 +281,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
|
||||
}
|
||||
Place {
|
||||
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() => {
|
||||
Place {
|
||||
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 +338,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Also suggest adding mut for upvars
|
||||
Place::Projection(box Projection {
|
||||
Place {
|
||||
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 +374,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 {
|
||||
Place {
|
||||
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 +389,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 {
|
||||
Place {
|
||||
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 +416,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() =>
|
||||
Place {
|
||||
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 +499,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Place::Projection(box Projection {
|
||||
Place {
|
||||
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 +516,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Place::Projection(box Projection {
|
||||
Place {
|
||||
base: _,
|
||||
elem: ProjectionElem::Deref,
|
||||
}) => {
|
||||
projection: Some(box Projection {
|
||||
base: _,
|
||||
elem: ProjectionElem::Deref,
|
||||
}),
|
||||
} => {
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
|
||||
match opt_source {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -489,8 +492,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 +540,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 +567,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 +580,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 +599,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 +636,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 +650,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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 Place {
|
||||
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.
|
||||
|
|
|
@ -11,7 +11,7 @@ use super::MirBorrowckCtxt;
|
|||
|
||||
use rustc::hir;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::mir::{Body, Place, PlaceBase, ProjectionElem};
|
||||
use rustc::mir::{Body, Place, PlaceBase, Projection, ProjectionElem};
|
||||
|
||||
pub trait IsPrefixOf<'tcx> {
|
||||
fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
|
||||
|
@ -19,18 +19,15 @@ pub trait IsPrefixOf<'tcx> {
|
|||
|
||||
impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
|
||||
fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
|
||||
let mut cursor = other;
|
||||
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<(&'cx PlaceBase<'tcx>, &'cx Option<Box<Projection<'tcx>>>)>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
|
@ -59,9 +56,14 @@ 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_base: &'cx PlaceBase<'tcx>,
|
||||
place_projection: &'cx Option<Box<Projection<'tcx>>>,
|
||||
kind: PrefixSet,
|
||||
) -> Prefixes<'cx, 'tcx> {
|
||||
Prefixes {
|
||||
next: Some(place),
|
||||
next: Some((place_base, place_projection)),
|
||||
kind,
|
||||
body: self.body,
|
||||
tcx: self.infcx.tcx,
|
||||
|
@ -70,7 +72,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
||||
type Item = &'cx Place<'tcx>;
|
||||
type Item = (&'cx PlaceBase<'tcx>, &'cx Option<Box<Projection<'tcx>>>);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut cursor = self.next?;
|
||||
|
||||
|
@ -80,27 +82,27 @@ 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 {
|
||||
(&PlaceBase::Local(_), &None)
|
||||
| // search yielded this leaf
|
||||
(&PlaceBase::Static(_), &None) => {
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
Place::Projection(ref proj) => proj,
|
||||
(_, &Some(ref 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((cursor.0, &proj.base));
|
||||
return Some(cursor);
|
||||
}
|
||||
ProjectionElem::Downcast(..) |
|
||||
ProjectionElem::Subslice { .. } |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
ProjectionElem::Index(_) => {
|
||||
cursor = &proj.base;
|
||||
cursor = (cursor.0, &proj.base);
|
||||
continue 'cursor;
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
|
@ -121,7 +123,7 @@ 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((cursor.0, &proj.base));
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::Supporting => {
|
||||
|
@ -134,7 +136,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.0, &proj.base, self.body, self.tcx).ty;
|
||||
match ty.sty {
|
||||
ty::RawPtr(_) |
|
||||
ty::Ref(
|
||||
|
@ -152,12 +154,12 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
_, /*ty*/
|
||||
hir::MutMutable,
|
||||
) => {
|
||||
self.next = Some(&proj.base);
|
||||
self.next = Some((cursor.0, &proj.base));
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
ty::Adt(..) if ty.is_box() => {
|
||||
self.next = Some(&proj.base);
|
||||
self.next = Some((cursor.0, &proj.base));
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 = Place {
|
||||
base: base.clone(),
|
||||
projection: base_proj.clone(),
|
||||
};
|
||||
|
||||
// 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,
|
||||
},
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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<(Place<'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(Place {
|
||||
base: place.base.clone(),
|
||||
projection: base.clone(),
|
||||
});
|
||||
}
|
||||
prefix_cursor = base;
|
||||
}
|
||||
|
||||
all_fake_borrows.push(place);
|
||||
all_fake_borrows.push(place.clone());
|
||||
}
|
||||
|
||||
// Deduplicate and ensure a deterministic order.
|
||||
|
@ -1339,7 +1345,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<(Place<'tcx>, Local)>,
|
||||
scrutinee_span: Span,
|
||||
region_scope: region::Scope,
|
||||
) -> BasicBlock {
|
||||
|
@ -1470,7 +1476,7 @@ 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,
|
||||
|
@ -1479,7 +1485,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.cfg.push_assign(
|
||||
block,
|
||||
scrutinee_source_info,
|
||||
&Place::from(temp),
|
||||
&Place::from(*temp),
|
||||
borrow,
|
||||
);
|
||||
}
|
||||
|
@ -1549,7 +1555,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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -423,21 +429,32 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
fn gather_init(&mut self, place: &Place<'tcx>, kind: InitKind) {
|
||||
debug!("gather_init({:?}, {:?})", self.loc, place);
|
||||
|
||||
let place = match place {
|
||||
let place = match place.projection {
|
||||
// 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,
|
||||
Some(box Projection {
|
||||
base: ref proj_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,
|
||||
}) => {
|
||||
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 { base: place.base.clone(), projection: proj_base.clone() }
|
||||
} else {
|
||||
place.clone()
|
||||
}
|
||||
} else {
|
||||
place.clone()
|
||||
}
|
||||
}
|
||||
|
||||
_ => place.clone()
|
||||
};
|
||||
|
||||
if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) {
|
||||
if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(&place) {
|
||||
let init = self.builder.data.inits.push(Init {
|
||||
location: InitLocation::Statement(self.loc),
|
||||
path,
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -17,32 +17,28 @@ pub struct AddRetag;
|
|||
fn is_stable(
|
||||
place: &Place<'_>,
|
||||
) -> 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(&Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, &Place {
|
||||
base: base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
});
|
||||
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,19 +206,37 @@ 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_)) => {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
} => Self::in_local(cx, local),
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(_),
|
||||
..
|
||||
}),
|
||||
projection: None,
|
||||
} => bug!("qualifying already promoted MIR"),
|
||||
Place {
|
||||
base: PlaceBase::Static(ref static_),
|
||||
projection: None,
|
||||
} => {
|
||||
Self::in_static(cx, static_)
|
||||
},
|
||||
Place::Projection(ref proj) => Self::in_projection(cx, proj),
|
||||
Place {
|
||||
ref base,
|
||||
projection: Some(ref proj),
|
||||
} => Self::in_projection(cx, &base, proj),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,11 +286,14 @@ 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, &Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.base.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,31 +854,39 @@ 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,
|
||||
&Place {
|
||||
base: base.clone(),
|
||||
projection: dest_projection.clone(),
|
||||
},
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
dest = &proj.base;
|
||||
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,
|
||||
&Place {
|
||||
base: dest.base.clone(),
|
||||
projection: dest_projection.clone(),
|
||||
},
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
|
@ -950,7 +991,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 +1003,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 +1090,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 +1099,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 +1130,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 +1167,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 +1186,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 +1210,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
MutatingUseContext::Borrow,
|
||||
),
|
||||
};
|
||||
self.visit_place(place, ctx, location);
|
||||
self.visit_place(&Place {
|
||||
base: place.base.clone(),
|
||||
projection: proj.clone(),
|
||||
}, ctx, location);
|
||||
} else {
|
||||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
@ -1428,7 +1482,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 +1715,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,
|
||||
..
|
||||
} => {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -187,7 +214,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
|
|||
None
|
||||
}).collect();
|
||||
|
||||
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
|
||||
let opt_src_place = items.first().and_then(|x| x.clone()).map(|x| x.2);
|
||||
let opt_size = opt_src_place.and_then(|src_place| {
|
||||
let src_ty = src_place.ty(body, tcx).ty;
|
||||
if let ty::Array(_, ref size_o) = src_ty.sty {
|
||||
|
@ -210,16 +237,17 @@ 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, Place<'tcx>)>],
|
||||
opt_size: Option<u64>,
|
||||
patch: &mut MirPatch<'tcx>,
|
||||
dst_place: &Place<'tcx>) {
|
||||
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
|
||||
let opt_src_place = items.first().and_then(|x| x.clone()).map(|x| x.2);
|
||||
|
||||
if opt_size.is_some() && items.iter().all(
|
||||
|l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
|
||||
|l| l.is_some() && l.clone().unwrap().2 == opt_src_place.clone().unwrap()) {
|
||||
let src_place = opt_src_place.clone().unwrap();
|
||||
|
||||
let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
|
||||
let indices: Vec<_> = items.iter().map(|x| x.clone().unwrap().1).collect();
|
||||
for i in 1..indices.len() {
|
||||
if indices[i - 1] + 1 != indices[i] {
|
||||
return;
|
||||
|
@ -230,7 +258,7 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
let max = *indices.last().unwrap();
|
||||
|
||||
for item in items {
|
||||
let locals_use = item.unwrap().0;
|
||||
let locals_use = item.clone().unwrap().0;
|
||||
patch.make_nop(locals_use.alive.unwrap());
|
||||
patch.make_nop(locals_use.dead.unwrap());
|
||||
patch.make_nop(locals_use.first_use.unwrap());
|
||||
|
@ -241,25 +269,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, Place<'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, Place {
|
||||
base: base.clone(),
|
||||
projection: proj_base.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue