Pattern match over PlaceRef rather than Place
This prepares the code base for when projection is interned. Place's projection field is going to be `&List<PlaceElem<'tcx>>` so we won't be able to pattern match against it.
This commit is contained in:
parent
270541221f
commit
190802cfca
37 changed files with 709 additions and 822 deletions
|
|
@ -1908,15 +1908,15 @@ 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),
|
||||
projection: box [],
|
||||
match self.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[],
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
} => Some(*local),
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[ProjectionElem::Deref],
|
||||
} => Some(local),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,10 +191,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(index) = place.as_local() {
|
||||
self.assign(index, location);
|
||||
let decl_span = self.fx.mir.local_decls[index].source_info.span;
|
||||
if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_index::vec::Idx;
|
|||
use rustc::middle::lang_items;
|
||||
use rustc::ty::{self, Ty, TypeFoldable, Instance};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
|
||||
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
|
||||
use rustc::mir::{self, PlaceBase, Static, StaticKind};
|
||||
use rustc::mir::interpret::PanicInfo;
|
||||
use rustc_target::abi::call::{ArgType, FnType, PassMode};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
|
@ -630,53 +630,43 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// checked by const-qualification, which also
|
||||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
|
||||
match *arg {
|
||||
match arg {
|
||||
// The shuffle array argument is usually not an explicit constant,
|
||||
// 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, _),
|
||||
mir::Operand::Copy(place) | mir::Operand::Move(place) => {
|
||||
if let mir::PlaceRef {
|
||||
base:
|
||||
&PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(promoted, _),
|
||||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: &[],
|
||||
} = place.as_ref()
|
||||
{
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
instance: self.instance,
|
||||
promoted: Some(promoted),
|
||||
};
|
||||
let c = bx.tcx().const_eval(param_env.and(cid));
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
terminator.source_info.span,
|
||||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: box [],
|
||||
c,
|
||||
);
|
||||
return OperandRef {
|
||||
val: Immediate(llval),
|
||||
layout: bx.layout_of(ty),
|
||||
};
|
||||
} else {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
) |
|
||||
mir::Operand::Move(
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(promoted, _),
|
||||
ty,
|
||||
def_id: _,
|
||||
}),
|
||||
projection: box [],
|
||||
}
|
||||
) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
instance: self.instance,
|
||||
promoted: Some(promoted),
|
||||
};
|
||||
let c = bx.tcx().const_eval(param_env.and(cid));
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
terminator.source_info.span,
|
||||
ty,
|
||||
c,
|
||||
);
|
||||
return OperandRef {
|
||||
val: Immediate(llval),
|
||||
layout: bx.layout_of(ty),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
mir::Operand::Copy(_) |
|
||||
mir::Operand::Move(_) => {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
mir::Operand::Constant(constant) => {
|
||||
let c = self.eval_mir_constant(constant);
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
|
|
@ -1117,10 +1107,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *dest {
|
||||
let dest = if let Some(index) = dest.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(dest) => dest,
|
||||
LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
|
||||
|
|
@ -1178,10 +1165,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *dst {
|
||||
if let Some(index) = dst.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
||||
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
|
||||
|
|
|
|||
|
|
@ -530,10 +530,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(index) = place.as_local() {
|
||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||
if let ty::Array(_, n) = op.layout.ty.kind {
|
||||
let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
|
||||
|
|
|
|||
|
|
@ -17,11 +17,8 @@ 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(box(ref place, ref rvalue)) => {
|
||||
if let mir::Place {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
} = place {
|
||||
match self.locals[*index] {
|
||||
if let Some(index) = place.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(cg_dest) => {
|
||||
self.codegen_rvalue(bx, cg_dest, rvalue)
|
||||
}
|
||||
|
|
@ -30,7 +27,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
LocalRef::Operand(None) => {
|
||||
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
|
||||
if let Some(name) = self.mir.local_decls[*index].name {
|
||||
if let Some(name) = self.mir.local_decls[index].name {
|
||||
match operand.val {
|
||||
OperandValue::Ref(x, ..) |
|
||||
OperandValue::Immediate(x) => {
|
||||
|
|
@ -44,7 +41,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.locals[*index] = LocalRef::Operand(Some(operand));
|
||||
self.locals[index] = LocalRef::Operand(Some(operand));
|
||||
bx
|
||||
}
|
||||
LocalRef::Operand(Some(op)) => {
|
||||
|
|
|
|||
|
|
@ -315,10 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
|||
// TEMP = &foo
|
||||
//
|
||||
// so extract `temp`.
|
||||
let temp = if let &mir::Place {
|
||||
base: mir::PlaceBase::Local(temp),
|
||||
projection: box [],
|
||||
} = assigned_place {
|
||||
let temp = if let Some(temp) = assigned_place.as_local() {
|
||||
temp
|
||||
} else {
|
||||
span_bug!(
|
||||
|
|
|
|||
|
|
@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
let span = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = place {
|
||||
let decl = &self.body.local_decls[*local];
|
||||
let span = if let Some(local) = place.as_local() {
|
||||
let decl = &self.body.local_decls[local];
|
||||
Some(decl.source_info.span)
|
||||
} else {
|
||||
None
|
||||
|
|
@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
projection,
|
||||
} = first_borrowed_place;
|
||||
|
||||
let mut cursor = &**projection;
|
||||
let mut cursor = projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
projection,
|
||||
} = second_borrowed_place;
|
||||
|
||||
let mut cursor = &**projection;
|
||||
let mut cursor = projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
@ -1124,26 +1121,22 @@ 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),
|
||||
projection: box [],
|
||||
} => {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer
|
||||
| LocalKind::Temp => bug!("temporary or return pointer with a name"),
|
||||
LocalKind::Var => "local variable ",
|
||||
LocalKind::Arg
|
||||
if !self.upvars.is_empty()
|
||||
&& local == Local::new(1) => {
|
||||
"variable captured by `move` "
|
||||
}
|
||||
LocalKind::Arg => {
|
||||
"function parameter "
|
||||
}
|
||||
let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer
|
||||
| LocalKind::Temp => bug!("temporary or return pointer with a name"),
|
||||
LocalKind::Var => "local variable ",
|
||||
LocalKind::Arg
|
||||
if !self.upvars.is_empty()
|
||||
&& local == Local::new(1) => {
|
||||
"variable captured by `move` "
|
||||
}
|
||||
LocalKind::Arg => {
|
||||
"function parameter "
|
||||
}
|
||||
}
|
||||
_ => "local data ",
|
||||
} else {
|
||||
"local data "
|
||||
};
|
||||
(
|
||||
format!("{}`{}`", local_kind, place_desc),
|
||||
|
|
@ -1480,10 +1473,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *err_place {
|
||||
let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
|
||||
if let LocalKind::Arg = self.body.local_kind(local) {
|
||||
(true, Some(&self.body.local_decls[local]))
|
||||
} else {
|
||||
|
|
@ -1643,11 +1633,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
reservation
|
||||
);
|
||||
// Check that the initial assignment of the reserve location is into a temporary.
|
||||
let mut target = *match reservation {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} if self.body.local_kind(*local) == LocalKind::Temp => local,
|
||||
let mut target = match reservation.as_local() {
|
||||
Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
|
@ -1659,127 +1646,122 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
|
||||
target, stmt
|
||||
);
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: box [],
|
||||
},
|
||||
rvalue
|
||||
)
|
||||
) = &stmt.kind {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}",
|
||||
assigned_to, rvalue
|
||||
);
|
||||
// Check if our `target` was captured by a closure.
|
||||
if let Rvalue::Aggregate(
|
||||
box AggregateKind::Closure(def_id, substs),
|
||||
operands,
|
||||
) = rvalue
|
||||
{
|
||||
for operand in operands {
|
||||
let assigned_from = match operand {
|
||||
if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
|
||||
if let Some(assigned_to) = place.as_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}",
|
||||
assigned_to, rvalue
|
||||
);
|
||||
// Check if our `target` was captured by a closure.
|
||||
if let Rvalue::Aggregate(
|
||||
box AggregateKind::Closure(def_id, substs),
|
||||
operands,
|
||||
) = rvalue
|
||||
{
|
||||
for operand in operands {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from
|
||||
);
|
||||
|
||||
// Find the local from the operand.
|
||||
let assigned_from_local = match assigned_from.local_or_deref_local()
|
||||
{
|
||||
Some(local) => local,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a closure captured our `target` and then assigned
|
||||
// into a place then we should annotate the closure in
|
||||
// case it ends up being assigned into the return place.
|
||||
annotated_closure = self.annotate_fn_sig(
|
||||
*def_id,
|
||||
self.infcx.closure_sig(*def_id, *substs),
|
||||
);
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
annotated_closure={:?} assigned_from_local={:?} \
|
||||
assigned_to={:?}",
|
||||
annotated_closure, assigned_from_local, assigned_to
|
||||
);
|
||||
|
||||
if assigned_to == mir::RETURN_PLACE {
|
||||
// If it was assigned directly into the return place, then
|
||||
// return now.
|
||||
return annotated_closure;
|
||||
} else {
|
||||
// Otherwise, update the target.
|
||||
target = assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
// If none of our closure's operands matched, then skip to the next
|
||||
// statement.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, look at other types of assignment.
|
||||
let assigned_from = match rvalue {
|
||||
Rvalue::Ref(_, _, assigned_from) => assigned_from,
|
||||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from
|
||||
);
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
|
||||
// Find the local from the operand.
|
||||
let assigned_from_local = match assigned_from.local_or_deref_local() {
|
||||
Some(local) => local,
|
||||
None => continue,
|
||||
};
|
||||
// Find the local from the rvalue.
|
||||
let assigned_from_local = match assigned_from.local_or_deref_local() {
|
||||
Some(local) => local,
|
||||
None => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a closure captured our `target` and then assigned
|
||||
// into a place then we should annotate the closure in
|
||||
// case it ends up being assigned into the return place.
|
||||
annotated_closure = self.annotate_fn_sig(
|
||||
*def_id,
|
||||
self.infcx.closure_sig(*def_id, *substs),
|
||||
);
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
annotated_closure={:?} assigned_from_local={:?} \
|
||||
assigned_to={:?}",
|
||||
annotated_closure, assigned_from_local, assigned_to
|
||||
);
|
||||
|
||||
if *assigned_to == mir::RETURN_PLACE {
|
||||
// If it was assigned directly into the return place, then
|
||||
// return now.
|
||||
return annotated_closure;
|
||||
} else {
|
||||
// Otherwise, update the target.
|
||||
target = *assigned_to;
|
||||
}
|
||||
// Check if our local matches the target - if so, we've assigned our
|
||||
// borrow to a new place.
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If none of our closure's operands matched, then skip to the next
|
||||
// statement.
|
||||
continue;
|
||||
// If we assigned our `target` into a new place, then we should
|
||||
// check if it was the return place.
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?} assigned_to={:?}",
|
||||
assigned_from_local, assigned_to
|
||||
);
|
||||
if assigned_to == mir::RETURN_PLACE {
|
||||
// If it was then return the annotated closure if there was one,
|
||||
// else, annotate this function.
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
|
||||
// If we didn't assign into the return place, then we just update
|
||||
// the target.
|
||||
target = assigned_to;
|
||||
}
|
||||
|
||||
// Otherwise, look at other types of assignment.
|
||||
let assigned_from = match rvalue {
|
||||
Rvalue::Ref(_, _, assigned_from) => assigned_from,
|
||||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
|
||||
// Find the local from the rvalue.
|
||||
let assigned_from_local = match assigned_from.local_or_deref_local() {
|
||||
Some(local) => local,
|
||||
None => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
// Check if our local matches the target - if so, we've assigned our
|
||||
// borrow to a new place.
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we assigned our `target` into a new place, then we should
|
||||
// check if it was the return place.
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?} assigned_to={:?}",
|
||||
assigned_from_local, assigned_to
|
||||
);
|
||||
if *assigned_to == mir::RETURN_PLACE {
|
||||
// If it was then return the annotated closure if there was one,
|
||||
// else, annotate this function.
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
|
||||
// If we didn't assign into the return place, then we just update
|
||||
// the target.
|
||||
target = *assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1790,38 +1772,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
target, terminator
|
||||
);
|
||||
if let TerminatorKind::Call {
|
||||
destination: Some((Place {
|
||||
base: PlaceBase::Local(assigned_to),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
destination: Some((place, _)),
|
||||
args,
|
||||
..
|
||||
} = &terminator.kind
|
||||
{
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
|
||||
assigned_to, args
|
||||
);
|
||||
for operand in args {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
if let Some(assigned_to) = place.as_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from,
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
|
||||
assigned_to, args
|
||||
);
|
||||
|
||||
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
|
||||
for operand in args {
|
||||
let assigned_from = match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
|
||||
if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
return annotated_closure.or_else(fallback);
|
||||
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -838,12 +838,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.get(location.statement_index)
|
||||
{
|
||||
Some(&Statement {
|
||||
kind: StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
kind: StatementKind::Assign(box(ref place, _)),
|
||||
..
|
||||
}) => local,
|
||||
}) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
return OtherUse(use_span);
|
||||
}
|
||||
}
|
||||
_ => return OtherUse(use_span),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1133,15 +1133,12 @@ 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),
|
||||
projection: box [],
|
||||
} = place_span.0 {
|
||||
if let Mutability::Not = self.body.local_decls[*local].mutability {
|
||||
if let Some(local) = place_span.0.as_local() {
|
||||
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,
|
||||
);
|
||||
|
|
@ -1288,59 +1285,57 @@ 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),
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||
// The variable will be marked as mutable by the borrow.
|
||||
return;
|
||||
Operand::Move(ref place) | Operand::Copy(ref place) => {
|
||||
match place.as_local() {
|
||||
Some(local) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||
// The variable will be marked as mutable by the borrow.
|
||||
return;
|
||||
}
|
||||
// This is an edge case where we have a `move` closure
|
||||
// inside a non-move closure, and the inner closure
|
||||
// contains a mutation:
|
||||
//
|
||||
// let mut i = 0;
|
||||
// || { move || { i += 1; }; };
|
||||
//
|
||||
// In this case our usual strategy of assuming that the
|
||||
// variable will be captured by mutable reference is
|
||||
// wrong, since `i` can be copied into the inner
|
||||
// closure from a shared reference.
|
||||
//
|
||||
// As such we have to search for the local that this
|
||||
// capture comes from and mark it as being used as mut.
|
||||
|
||||
let temp_mpi = self.move_data.rev_lookup.find_local(local);
|
||||
let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
|
||||
&self.move_data.inits[init_index]
|
||||
} else {
|
||||
bug!("temporary should be initialized exactly once")
|
||||
};
|
||||
|
||||
let loc = match init.location {
|
||||
InitLocation::Statement(stmt) => stmt,
|
||||
_ => bug!("temporary initialized in arguments"),
|
||||
};
|
||||
|
||||
let bbd = &self.body[loc.block];
|
||||
let stmt = &bbd.statements[loc.statement_index];
|
||||
debug!("temporary assigned in: stmt={:?}", stmt);
|
||||
|
||||
if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref source))) =
|
||||
stmt.kind
|
||||
{
|
||||
propagate_closure_used_mut_place(self, source);
|
||||
} else {
|
||||
bug!(
|
||||
"closures should only capture user variables \
|
||||
or references to user variables"
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => propagate_closure_used_mut_place(self, place),
|
||||
}
|
||||
// This is an edge case where we have a `move` closure
|
||||
// inside a non-move closure, and the inner closure
|
||||
// contains a mutation:
|
||||
//
|
||||
// let mut i = 0;
|
||||
// || { move || { i += 1; }; };
|
||||
//
|
||||
// In this case our usual strategy of assuming that the
|
||||
// variable will be captured by mutable reference is
|
||||
// wrong, since `i` can be copied into the inner
|
||||
// closure from a shared reference.
|
||||
//
|
||||
// As such we have to search for the local that this
|
||||
// capture comes from and mark it as being used as mut.
|
||||
|
||||
let temp_mpi = self.move_data.rev_lookup.find_local(local);
|
||||
let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
|
||||
&self.move_data.inits[init_index]
|
||||
} else {
|
||||
bug!("temporary should be initialized exactly once")
|
||||
};
|
||||
|
||||
let loc = match init.location {
|
||||
InitLocation::Statement(stmt) => stmt,
|
||||
_ => bug!("temporary initialized in arguments"),
|
||||
};
|
||||
|
||||
let bbd = &self.body[loc.block];
|
||||
let stmt = &bbd.statements[loc.statement_index];
|
||||
debug!("temporary assigned in: stmt={:?}", stmt);
|
||||
|
||||
if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
|
||||
propagate_closure_used_mut_place(self, source);
|
||||
} else {
|
||||
bug!("closures should only capture user variables \
|
||||
or references to user variables");
|
||||
}
|
||||
}
|
||||
Operand::Move(ref place)
|
||||
| Operand::Copy(ref place) => {
|
||||
propagate_closure_used_mut_place(self, place);
|
||||
}
|
||||
Operand::Constant(..) => {}
|
||||
}
|
||||
|
|
@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||
|
||||
// None case => assigning to `x` does not require `x` be initialized.
|
||||
let mut cursor = &*place.projection;
|
||||
let mut cursor = &*place.projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,45 +89,41 @@ 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(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(move_from))
|
||||
)
|
||||
box(place, Rvalue::Use(Operand::Move(move_from)))
|
||||
)) = self.body.basic_blocks()[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
.map(|stmt| &stmt.kind)
|
||||
{
|
||||
let local_decl = &self.body.local_decls[*local];
|
||||
// opt_match_place is the
|
||||
// match_span is the span of the expression being matched on
|
||||
// match *x.y { ... } match_place is Some(*x.y)
|
||||
// ^^^^ match_span is the span of *x.y
|
||||
//
|
||||
// opt_match_place is None for let [mut] x = ... statements,
|
||||
// whether or not the right-hand side is a place expression
|
||||
if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((ref opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
}))) = local_decl.is_user_variable
|
||||
{
|
||||
let stmt_source_info = self.body.source_info(location);
|
||||
self.append_binding_error(
|
||||
grouped_errors,
|
||||
kind,
|
||||
original_path,
|
||||
move_from,
|
||||
*local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
stmt_source_info.span,
|
||||
);
|
||||
return;
|
||||
if let Some(local) = place.as_local() {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
// opt_match_place is the
|
||||
// match_span is the span of the expression being matched on
|
||||
// match *x.y { ... } match_place is Some(*x.y)
|
||||
// ^^^^ match_span is the span of *x.y
|
||||
//
|
||||
// opt_match_place is None for let [mut] x = ... statements,
|
||||
// whether or not the right-hand side is a place expression
|
||||
if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((ref opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
}))) = local_decl.is_user_variable
|
||||
{
|
||||
let stmt_source_info = self.body.source_info(location);
|
||||
self.append_binding_error(
|
||||
grouped_errors,
|
||||
kind,
|
||||
original_path,
|
||||
move_from,
|
||||
local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
stmt_source_info.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
|
||||
.find_map(|p| self.is_upvar_field_projection(p));
|
||||
|
||||
let deref_base = match &deref_target_place.projection {
|
||||
box [proj_base @ .., ProjectionElem::Deref] => {
|
||||
let deref_base = match deref_target_place.projection.as_ref() {
|
||||
&[ref proj_base @ .., ProjectionElem::Deref] => {
|
||||
PlaceRef {
|
||||
base: &deref_target_place.base,
|
||||
projection: proj_base,
|
||||
projection: &proj_base,
|
||||
}
|
||||
}
|
||||
_ => bug!("deref_target_place is not a deref projection"),
|
||||
|
|
|
|||
|
|
@ -49,10 +49,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
projection: [],
|
||||
} => {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
if let Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
} = access_place {
|
||||
if access_place.as_local().is_some() {
|
||||
reason = ", as it is not declared as mutable".to_string();
|
||||
} else {
|
||||
let name = self.body.local_decls[*local]
|
||||
|
|
@ -153,10 +150,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}),
|
||||
projection: [],
|
||||
} => {
|
||||
if let Place {
|
||||
base: PlaceBase::Static(_),
|
||||
projection: box [],
|
||||
} = access_place {
|
||||
if let PlaceRef {
|
||||
base: &PlaceBase::Static(_),
|
||||
projection: &[],
|
||||
} = access_place.as_ref() {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
reason = String::new();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use rustc::infer::InferCtxt;
|
|||
use rustc::mir::visit::TyContext;
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::{
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem,
|
||||
Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, RegionVid, Ty};
|
||||
|
|
@ -211,14 +211,14 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
// - if it's a deeper projection, we have to filter which
|
||||
// of the borrows are killed: the ones whose `borrowed_place`
|
||||
// conflicts with the `place`.
|
||||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
match place.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[],
|
||||
} |
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[ProjectionElem::Deref],
|
||||
} => {
|
||||
debug!(
|
||||
"Recording `killed` facts for borrows of local={:?} at location={:?}",
|
||||
|
|
@ -229,21 +229,21 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
all_facts,
|
||||
self.borrow_set,
|
||||
self.location_table,
|
||||
local,
|
||||
&local,
|
||||
location,
|
||||
);
|
||||
}
|
||||
|
||||
Place {
|
||||
base: PlaceBase::Static(_),
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Static(_),
|
||||
..
|
||||
} => {
|
||||
// Ignore kills of static or static mut variables.
|
||||
}
|
||||
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [.., _],
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[.., _],
|
||||
} => {
|
||||
// Kill conflicting borrows of the innermost local.
|
||||
debug!(
|
||||
|
|
@ -252,7 +252,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
local, location
|
||||
);
|
||||
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
|
||||
for &borrow_index in borrow_indices {
|
||||
let places_conflict = places_conflict::places_conflict(
|
||||
self.infcx.tcx,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionName};
|
|||
use crate::borrow_check::nll::ConstraintDescription;
|
||||
use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
|
||||
use rustc::mir::{
|
||||
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase,
|
||||
Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
|
||||
Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::adjustment::{PointerCast};
|
||||
|
|
@ -273,12 +273,9 @@ 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),
|
||||
projection: box [],
|
||||
} = place {
|
||||
if body.local_decls[*borrowed_local].name.is_some()
|
||||
&& local != *borrowed_local
|
||||
if let Some(borrowed_local) = place.as_local() {
|
||||
if body.local_decls[borrowed_local].name.is_some()
|
||||
&& local != borrowed_local
|
||||
{
|
||||
should_note_order = true;
|
||||
}
|
||||
|
|
@ -494,22 +491,19 @@ 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),
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
}) => {
|
||||
let local_decl = &self.body.local_decls[*l];
|
||||
if local_decl.name.is_none() {
|
||||
local_decl.source_info.span
|
||||
Operand::Copy(place) |
|
||||
Operand::Move(place) => {
|
||||
if let Some(l) = place.as_local() {
|
||||
let local_decl = &self.body.local_decls[l];
|
||||
if local_decl.name.is_none() {
|
||||
local_decl.source_info.span
|
||||
} else {
|
||||
span
|
||||
}
|
||||
} else {
|
||||
span
|
||||
}
|
||||
}
|
||||
_ => span,
|
||||
};
|
||||
return (LaterUseKind::Call, function_span);
|
||||
} else {
|
||||
|
|
@ -542,14 +536,14 @@ 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(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}, _)),
|
||||
kind: StatementKind::Assign(box(ref place, _)),
|
||||
..
|
||||
}) = stmt
|
||||
{
|
||||
local
|
||||
}) = stmt {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
|
@ -582,17 +576,13 @@ 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),
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
if *from == target =>
|
||||
{
|
||||
target = into;
|
||||
Operand::Copy(place)
|
||||
| Operand::Move(place) => {
|
||||
if let Some(from) = place.as_local() {
|
||||
if from == target {
|
||||
target = into;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
|
@ -601,28 +591,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Rvalue::Cast(
|
||||
CastKind::Pointer(PointerCast::Unsize), operand, ty
|
||||
) => match operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(from),
|
||||
projection: box [],
|
||||
})
|
||||
if *from == target =>
|
||||
{
|
||||
debug!("was_captured_by_trait_object: ty={:?}", ty);
|
||||
// Check the type for a trait object.
|
||||
return match ty.kind {
|
||||
// `&dyn Trait`
|
||||
ty::Ref(_, ty, _) if ty.is_trait() => true,
|
||||
// `Box<dyn Trait>`
|
||||
_ if ty.is_box() && ty.boxed_ty().is_trait() => true,
|
||||
// `dyn Trait`
|
||||
_ if ty.is_trait() => true,
|
||||
// Anything else.
|
||||
_ => false,
|
||||
};
|
||||
Operand::Copy(place)
|
||||
| Operand::Move(place) => {
|
||||
if let Some(from) = place.as_local() {
|
||||
if from == target {
|
||||
debug!("was_captured_by_trait_object: ty={:?}", ty);
|
||||
// Check the type for a trait object.
|
||||
return match ty.kind {
|
||||
// `&dyn Trait`
|
||||
ty::Ref(_, ty, _) if ty.is_trait() => true,
|
||||
// `Box<dyn Trait>`
|
||||
_ if ty.is_box() && ty.boxed_ty().is_trait() => true,
|
||||
// `dyn Trait`
|
||||
_ if ty.is_trait() => true,
|
||||
// Anything else.
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_ => return false,
|
||||
},
|
||||
|
|
@ -638,34 +625,33 @@ 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),
|
||||
projection: box [],
|
||||
}, block)),
|
||||
destination: Some((place, block)),
|
||||
args,
|
||||
..
|
||||
} = &terminator.kind
|
||||
{
|
||||
debug!(
|
||||
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
|
||||
target, dest, args
|
||||
);
|
||||
// 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),
|
||||
projection: box [],
|
||||
}) = arg {
|
||||
*potential == target
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
} = &terminator.kind {
|
||||
if let Some(dest) = place.as_local() {
|
||||
debug!(
|
||||
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
|
||||
target, dest, args
|
||||
);
|
||||
// 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) = arg {
|
||||
if let Some(potential) = place.as_local() {
|
||||
potential == target
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// If it is, follow this to the next block and update the target.
|
||||
if found_target {
|
||||
target = *dest;
|
||||
queue.push(block.start_location());
|
||||
// If it is, follow this to the next block and update the target.
|
||||
if found_target {
|
||||
target = dest;
|
||||
queue.push(block.start_location());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -480,13 +480,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
if place.projection.is_empty() {
|
||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||
let is_promoted = match place {
|
||||
Place {
|
||||
base: PlaceBase::Static(box Static {
|
||||
let is_promoted = match place.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Static(box Static {
|
||||
kind: StaticKind::Promoted(..),
|
||||
..
|
||||
}),
|
||||
projection: box [],
|
||||
projection: &[],
|
||||
} => true,
|
||||
_ => false,
|
||||
};
|
||||
|
|
@ -1366,11 +1366,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// they are not caused by the user, but rather artifacts
|
||||
// of lowering. Assignments to other sorts of places *are* interesting
|
||||
// though.
|
||||
let category = match *place {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: box [],
|
||||
} => if let BorrowCheckContext {
|
||||
let category = match place.as_local() {
|
||||
Some(RETURN_PLACE) => if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions {
|
||||
defining_ty: DefiningTy::Const(def_id, _),
|
||||
|
|
@ -1386,10 +1383,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
} else {
|
||||
ConstraintCategory::Return
|
||||
},
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
_ => ConstraintCategory::Assignment,
|
||||
|
|
@ -1675,11 +1669,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
Some((ref dest, _target_block)) => {
|
||||
let dest_ty = dest.ty(body, tcx).ty;
|
||||
let dest_ty = self.normalize(dest_ty, term_location);
|
||||
let category = match *dest {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: box [],
|
||||
} => {
|
||||
let category = match dest.as_local() {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let BorrowCheckContext {
|
||||
universal_regions:
|
||||
UniversalRegions {
|
||||
|
|
@ -1698,10 +1689,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ConstraintCategory::Return
|
||||
}
|
||||
}
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
} if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
_ => ConstraintCategory::Assignment,
|
||||
|
|
@ -2432,7 +2420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
location, borrow_region, borrowed_place
|
||||
);
|
||||
|
||||
let mut cursor = &*borrowed_place.projection;
|
||||
let mut cursor = borrowed_place.projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
|
|||
|
|
@ -64,14 +64,8 @@ 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),
|
||||
projection: box [],
|
||||
} = borrow_place {
|
||||
if let PlaceRef {
|
||||
base: PlaceBase::Local(l2),
|
||||
projection: [],
|
||||
} = access_place {
|
||||
if let Some(l1) = borrow_place.as_local() {
|
||||
if let Some(l2) = access_place.as_local() {
|
||||
return l1 == l2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::{
|
||||
Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind
|
||||
};
|
||||
use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
|
|
@ -118,10 +116,7 @@ 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),
|
||||
projection: box [],
|
||||
} = path.place {
|
||||
if let Some(user_local) = path.place.as_local() {
|
||||
self.mbcx.used_mut.insert(user_local);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -496,14 +496,14 @@ 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),
|
||||
projection: box [],
|
||||
let mutability = match arg_place.as_ref() {
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[],
|
||||
} => this.local_decls[local].mutability,
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [ProjectionElem::Deref],
|
||||
PlaceRef {
|
||||
base: &PlaceBase::Local(local),
|
||||
projection: &[ProjectionElem::Deref],
|
||||
} => {
|
||||
debug_assert!(
|
||||
this.local_decls[local].is_ref_for_guard(),
|
||||
|
|
@ -511,13 +511,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
);
|
||||
this.local_decls[local].mutability
|
||||
}
|
||||
Place {
|
||||
PlaceRef {
|
||||
ref base,
|
||||
projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
|
||||
}
|
||||
| Place {
|
||||
| PlaceRef {
|
||||
ref base,
|
||||
projection: box [
|
||||
projection: &[
|
||||
ref proj_base @ ..,
|
||||
ProjectionElem::Field(upvar_index, _),
|
||||
ProjectionElem::Deref
|
||||
|
|
|
|||
|
|
@ -1293,7 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
||||
for place in fake_borrows
|
||||
{
|
||||
let mut cursor = &*place.projection;
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
|
|
|
|||
|
|
@ -926,46 +926,43 @@ 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),
|
||||
projection: box [],
|
||||
})
|
||||
| Operand::Move(Place {
|
||||
base: PlaceBase::Local(cond_temp),
|
||||
projection: box [],
|
||||
}) => {
|
||||
// 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();
|
||||
Operand::Copy(place)
|
||||
| Operand::Move(place) => {
|
||||
if let Some(cond_temp) = place.as_local() {
|
||||
// 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();
|
||||
|
||||
match top_drop_data.kind {
|
||||
DropKind::Value { .. } => {
|
||||
bug!("Drop scheduled on top of condition variable")
|
||||
}
|
||||
DropKind::Storage => {
|
||||
let source_info = top_scope.source_info(top_drop_data.span);
|
||||
let local = top_drop_data.local;
|
||||
assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
|
||||
self.cfg.push(
|
||||
true_block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::StorageDead(local)
|
||||
},
|
||||
);
|
||||
self.cfg.push(
|
||||
false_block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::StorageDead(local)
|
||||
},
|
||||
);
|
||||
match top_drop_data.kind {
|
||||
DropKind::Value { .. } => {
|
||||
bug!("Drop scheduled on top of condition variable")
|
||||
}
|
||||
DropKind::Storage => {
|
||||
let source_info = top_scope.source_info(top_drop_data.span);
|
||||
let local = top_drop_data.local;
|
||||
assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
|
||||
self.cfg.push(
|
||||
true_block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::StorageDead(local)
|
||||
},
|
||||
);
|
||||
self.cfg.push(
|
||||
false_block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::StorageDead(local)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
top_scope.invalidate_cache(true, self.is_generator, true);
|
||||
} else {
|
||||
bug!("Expected as_local_operand to produce a temporary");
|
||||
}
|
||||
|
||||
top_scope.invalidate_cache(true, self.is_generator, true);
|
||||
}
|
||||
_ => bug!("Expected as_local_operand to produce a temporary"),
|
||||
}
|
||||
|
||||
(true_block, false_block)
|
||||
|
|
|
|||
|
|
@ -157,10 +157,12 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
// Since `propagate_call_unwind` doesn't exist, we have to kill the
|
||||
// destination here, and then gen it again in `propagate_call_return`.
|
||||
if let TerminatorKind::Call {
|
||||
destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)),
|
||||
destination: Some((ref place, _)),
|
||||
..
|
||||
} = self.body[loc.block].terminator().kind {
|
||||
sets.kill(local);
|
||||
if let Some(local) = place.as_local() {
|
||||
sets.kill(local);
|
||||
}
|
||||
}
|
||||
self.check_for_move(sets, loc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
|
|||
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
|
||||
loop {
|
||||
let path = &self.move_paths[mpi];
|
||||
if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
|
||||
if let Some(l) = path.place.as_local() {
|
||||
return Some(l);
|
||||
}
|
||||
if let Some(parent) = path.parent {
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ pub trait Qualif {
|
|||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if ProjectionElem::Deref == *elem {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if ProjectionElem::Deref == elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, per_local, PlaceRef {
|
||||
|
|
|
|||
|
|
@ -56,16 +56,16 @@ where
|
|||
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
|
||||
debug_assert!(!place.is_indirect());
|
||||
|
||||
match (value, place) {
|
||||
(true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => {
|
||||
self.qualifs_per_local.insert(*local);
|
||||
match (value, place.as_ref()) {
|
||||
(true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
|
||||
self.qualifs_per_local.insert(local);
|
||||
}
|
||||
|
||||
// For now, we do not clear the qualif if a local is overwritten in full by
|
||||
// an unqualified rvalue (e.g. `y = 5`). This is to be consistent
|
||||
// with aggregates where we overwrite all fields with assignments, which would not
|
||||
// get this feature.
|
||||
(false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => {
|
||||
(false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => {
|
||||
// self.qualifs_per_local.remove(*local);
|
||||
}
|
||||
|
||||
|
|
@ -101,11 +101,10 @@ where
|
|||
|
||||
// If a local with no projections is moved from (e.g. `x` in `y = x`), record that
|
||||
// it no longer needs to be dropped.
|
||||
if let mir::Operand::Move(mir::Place {
|
||||
base: mir::PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) = *operand {
|
||||
self.qualifs_per_local.remove(local);
|
||||
if let mir::Operand::Move(place) = operand {
|
||||
if let Some(local) = place.as_local() {
|
||||
self.qualifs_per_local.remove(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -244,8 +244,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
||||
// Special-case reborrows to be more like a copy of a reference.
|
||||
let mut reborrow_place = None;
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if *elem == ProjectionElem::Deref {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if elem == ProjectionElem::Deref {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
reborrow_place = Some(proj_base);
|
||||
|
|
@ -376,12 +376,15 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
);
|
||||
|
||||
if rvalue_has_mut_interior {
|
||||
let is_derived_from_illegal_borrow = match *borrowed_place {
|
||||
let is_derived_from_illegal_borrow = match borrowed_place.as_local() {
|
||||
// If an unprojected local was borrowed and its value was the result of an
|
||||
// illegal borrow, suppress this error and mark the result of this borrow as
|
||||
// illegal as well.
|
||||
Place { base: PlaceBase::Local(borrowed_local), projection: box [] }
|
||||
if self.derived_from_illegal_borrow.contains(borrowed_local) => true,
|
||||
Some(borrowed_local)
|
||||
if self.derived_from_illegal_borrow.contains(borrowed_local) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
|
||||
// Otherwise proceed normally: check the legality of a mutable borrow in this
|
||||
// context.
|
||||
|
|
@ -394,7 +397,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
// FIXME: should we also clear `derived_from_illegal_borrow` when a local is
|
||||
// assigned a new value?
|
||||
if is_derived_from_illegal_borrow {
|
||||
if let Place { base: PlaceBase::Local(dest), projection: box [] } = *dest {
|
||||
if let Some(dest) = dest.as_local() {
|
||||
self.derived_from_illegal_borrow.insert(dest);
|
||||
}
|
||||
}
|
||||
|
|
@ -571,10 +574,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let needs_drop = if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *dropped_place {
|
||||
let needs_drop = if let Some(local) = dropped_place.as_local() {
|
||||
// Use the span where the local was declared as the span of the drop error.
|
||||
err_span = self.body.local_decls[local].source_info.span;
|
||||
self.qualifs.needs_drop.contains(local)
|
||||
|
|
|
|||
|
|
@ -407,8 +407,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
is_mut_use: bool,
|
||||
) {
|
||||
let mut cursor = &*place.projection;
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
match elem {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@ use std::cell::Cell;
|
|||
use rustc::hir::def::DefKind;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{
|
||||
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
|
||||
Local, UnOp, StatementKind, Statement, LocalKind,
|
||||
TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp,
|
||||
SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
|
||||
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp,
|
||||
StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo,
|
||||
BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
|
||||
};
|
||||
use rustc::mir::visit::{
|
||||
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
|
||||
|
|
@ -525,18 +524,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// (e.g. for CTFE) it can never happen. But here in const_prop
|
||||
// unknown data is uninitialized, so if e.g. a function argument is unsized
|
||||
// and has a reference taken, we get an ICE.
|
||||
Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => {
|
||||
trace!("checking Ref({:?})", place);
|
||||
let alive =
|
||||
if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Rvalue::Ref(_, _, place_ref) => {
|
||||
trace!("checking Ref({:?})", place_ref);
|
||||
|
||||
if !alive {
|
||||
trace!("skipping Ref({:?}) to uninitialized local", place);
|
||||
return None;
|
||||
if let Some(local) = place_ref.as_local() {
|
||||
let alive =
|
||||
if let LocalValue::Live(_) = self.ecx.frame().locals[local].value {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !alive {
|
||||
trace!("skipping Ref({:?}) to uninitialized local", place);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -706,10 +708,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
.ty(&self.local_decls, self.tcx)
|
||||
.ty;
|
||||
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
|
||||
if let Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(local) = place.as_local() {
|
||||
let source = statement.source_info;
|
||||
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
|
||||
if self.can_const_prop[local] {
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@
|
|||
//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
|
||||
//! future.
|
||||
|
||||
use rustc::mir::{
|
||||
Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind
|
||||
};
|
||||
use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind};
|
||||
use rustc::mir::visit::MutVisitor;
|
||||
use rustc::ty::TyCtxt;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
|
@ -92,28 +90,32 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
};
|
||||
|
||||
// That use of the source must be an assignment.
|
||||
match statement.kind {
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(ref operand)
|
||||
)
|
||||
) if local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
Operand::Copy(ref src_place) |
|
||||
Operand::Move(ref src_place) => {
|
||||
Action::local_copy(&body, &def_use_analysis, src_place)
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box(place, Rvalue::Use(operand))) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == dest_local {
|
||||
let maybe_action = match operand {
|
||||
Operand::Copy(ref src_place) |
|
||||
Operand::Move(ref src_place) => {
|
||||
Action::local_copy(&body, &def_use_analysis, src_place)
|
||||
}
|
||||
Operand::Constant(ref src_constant) => {
|
||||
Action::constant(src_constant)
|
||||
}
|
||||
};
|
||||
match maybe_action {
|
||||
Some(this_action) => action = this_action,
|
||||
None => continue,
|
||||
}
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source use is not an \
|
||||
assignment");
|
||||
continue
|
||||
}
|
||||
Operand::Constant(ref src_constant) => {
|
||||
Action::constant(src_constant)
|
||||
}
|
||||
};
|
||||
match maybe_action {
|
||||
Some(this_action) => action = this_action,
|
||||
None => continue,
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source use is not an \
|
||||
assignment");
|
||||
continue
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -148,31 +150,20 @@ fn eliminate_self_assignments(
|
|||
for def in dest_use_info.defs_not_including_drop() {
|
||||
let location = def.location;
|
||||
if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Copy(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: box [],
|
||||
})),
|
||||
)
|
||||
) |
|
||||
StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: PlaceBase::Local(src_local),
|
||||
projection: box [],
|
||||
})),
|
||||
)
|
||||
) if local == dest_local && dest_local == src_local => {}
|
||||
match &stmt.kind {
|
||||
StatementKind::Assign(box (place, Rvalue::Use(Operand::Copy(src_place))))
|
||||
| StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(src_place)))) => {
|
||||
if let (Some(local), Some(src_local)) =
|
||||
(place.as_local(), src_place.as_local())
|
||||
{
|
||||
if local == dest_local && dest_local == src_local {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -198,10 +189,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *src_place {
|
||||
let src_local = if let Some(local) = src_place.as_local() {
|
||||
local
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source is not a local");
|
||||
|
|
@ -354,15 +342,18 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
|||
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
|
||||
self.super_operand(operand, location);
|
||||
|
||||
match *operand {
|
||||
Operand::Copy(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) |
|
||||
Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) if local == self.dest_local => {}
|
||||
match operand {
|
||||
Operand::Copy(place) |
|
||||
Operand::Move(place) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == self.dest_local {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -864,17 +864,24 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
|
|||
|
||||
for (block, block_data) in body.basic_blocks().iter_enumerated() {
|
||||
let (target, unwind, source_info) = match block_data.terminator() {
|
||||
&Terminator {
|
||||
Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Drop {
|
||||
location: Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
},
|
||||
location,
|
||||
target,
|
||||
unwind
|
||||
}
|
||||
} if local == gen => (target, unwind, source_info),
|
||||
} => {
|
||||
if let Some(local) = location.as_local() {
|
||||
if local == gen {
|
||||
(target, unwind, source_info)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
let unwind = if block_data.is_cleanup {
|
||||
|
|
@ -884,10 +891,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
|
|||
};
|
||||
elaborate_drop(
|
||||
&mut elaborator,
|
||||
source_info,
|
||||
*source_info,
|
||||
&Place::from(gen),
|
||||
(),
|
||||
target,
|
||||
*target,
|
||||
unwind,
|
||||
block,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -587,13 +587,12 @@ impl Inliner<'tcx> {
|
|||
// FIXME: Analysis of the usage of the arguments to avoid
|
||||
// unnecessary temporaries.
|
||||
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) = arg {
|
||||
if caller_body.local_kind(local) == LocalKind::Temp {
|
||||
// Reuse the operand if it's a temporary already
|
||||
return local;
|
||||
if let Operand::Move(place) = &arg {
|
||||
if let Some(local) = place.as_local() {
|
||||
if caller_body.local_kind(local) == LocalKind::Temp {
|
||||
// Reuse the operand if it's a temporary already
|
||||
return local;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -650,14 +649,9 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||
|
||||
fn make_integrate_local(&self, local: &Local) -> Local {
|
||||
if *local == RETURN_PLACE {
|
||||
match self.destination {
|
||||
Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: box [],
|
||||
} => {
|
||||
return l;
|
||||
},
|
||||
ref place => bug!("Return place is {:?}, not local", place)
|
||||
match self.destination.as_local() {
|
||||
Some(l) => return l,
|
||||
ref place => bug!("Return place is {:?}, not local", place),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -686,17 +680,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||
context: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
match place {
|
||||
Place {
|
||||
base: PlaceBase::Local(RETURN_PLACE),
|
||||
projection: box [],
|
||||
} => {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
},
|
||||
_ => {
|
||||
self.super_place(place, context, location);
|
||||
}
|
||||
if let Some(RETURN_PLACE) = place.as_local() {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
} else {
|
||||
self.super_place(place, context, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
//! Performs various peephole optimizations.
|
||||
|
||||
use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue,
|
||||
Local};
|
||||
use rustc::mir::{
|
||||
Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local
|
||||
};
|
||||
use rustc::mir::visit::{MutVisitor, Visitor};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
|
@ -40,20 +41,18 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
|||
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
|
||||
if self.optimizations.and_stars.remove(&location) {
|
||||
debug!("replacing `&*`: {:?}", rvalue);
|
||||
let new_place = match *rvalue {
|
||||
Rvalue::Ref(_, _, Place {
|
||||
ref mut base,
|
||||
projection: ref mut projection @ box [.., _],
|
||||
}) => {
|
||||
if let box [proj_l @ .., proj_r] = projection {
|
||||
let place = Place {
|
||||
// Replace with dummy
|
||||
base: mem::replace(base, PlaceBase::Local(Local::new(0))),
|
||||
projection: proj_l.to_vec().into_boxed_slice(),
|
||||
};
|
||||
*projection = vec![proj_r.clone()].into_boxed_slice();
|
||||
let new_place = match rvalue {
|
||||
Rvalue::Ref(_, _, place) => {
|
||||
if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() {
|
||||
let new_projection = proj_l.to_vec().into_boxed_slice();
|
||||
|
||||
place
|
||||
place.projection = vec![proj_r.clone()].into_boxed_slice();
|
||||
|
||||
Place {
|
||||
// Replace with dummy
|
||||
base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))),
|
||||
projection: new_projection,
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
|
@ -91,12 +90,14 @@ 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 {
|
||||
base,
|
||||
projection: box [proj_base @ .., ProjectionElem::Deref],
|
||||
}) = rvalue {
|
||||
if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
|
||||
self.optimizations.and_stars.insert(location);
|
||||
if let Rvalue::Ref(_, _, place) = rvalue {
|
||||
if let PlaceRef {
|
||||
base,
|
||||
projection: &[ref proj_base @ .., ProjectionElem::Deref],
|
||||
} = place.as_ref() {
|
||||
if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
|
||||
self.optimizations.and_stars.insert(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -434,14 +434,13 @@ pub fn promote_candidates<'tcx>(
|
|||
match candidate {
|
||||
Candidate::Repeat(Location { block, statement_index }) |
|
||||
Candidate::Ref(Location { block, statement_index }) => {
|
||||
match body[block].statements[statement_index].kind {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}, _)) => {
|
||||
if temps[local] == TempState::PromotedOut {
|
||||
// Already promoted.
|
||||
continue;
|
||||
match &body[block].statements[statement_index].kind {
|
||||
StatementKind::Assign(box(place, _)) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if temps[local] == TempState::PromotedOut {
|
||||
// Already promoted.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -487,28 +486,30 @@ pub fn promote_candidates<'tcx>(
|
|||
let promoted = |index: Local| temps[index] == TempState::PromotedOut;
|
||||
for block in body.basic_blocks_mut() {
|
||||
block.statements.retain(|statement| {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
}, _)) |
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box(place, _)) => {
|
||||
if let Some(index) = place.as_local() {
|
||||
!promoted(index)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(index) |
|
||||
StatementKind::StorageDead(index) => {
|
||||
!promoted(index)
|
||||
!promoted(*index)
|
||||
}
|
||||
_ => true
|
||||
}
|
||||
});
|
||||
let terminator = block.terminator_mut();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { location: Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
}, target, .. } => {
|
||||
if promoted(index) {
|
||||
terminator.kind = TerminatorKind::Goto {
|
||||
target,
|
||||
};
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Drop { location: place, target, .. } => {
|
||||
if let Some(index) = place.as_local() {
|
||||
if promoted(index) {
|
||||
terminator.kind = TerminatorKind::Goto {
|
||||
target: *target,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -292,8 +292,8 @@ trait Qualif {
|
|||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let box [proj_base @ .., elem] = &place.projection {
|
||||
if ProjectionElem::Deref == *elem {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if ProjectionElem::Deref == elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, PlaceRef {
|
||||
|
|
@ -1041,26 +1041,24 @@ 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),
|
||||
projection: box [],
|
||||
}),
|
||||
Operand::Move(place),
|
||||
_
|
||||
))) = self.body[bb].statements[stmt_idx].kind {
|
||||
promoted_temps.insert(index);
|
||||
))) = &self.body[bb].statements[stmt_idx].kind {
|
||||
if let Some(index) = place.as_local() {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
_,
|
||||
Rvalue::Ref(_, _, Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
})
|
||||
Rvalue::Ref(_, _, place)
|
||||
)
|
||||
) = self.body[bb].statements[stmt_idx].kind {
|
||||
promoted_temps.insert(index);
|
||||
) = &self.body[bb].statements[stmt_idx].kind {
|
||||
if let Some(index) = place.as_local() {
|
||||
promoted_temps.insert(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
Candidate::Argument { .. } => {}
|
||||
|
|
@ -1237,10 +1235,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
if let Some(local) = place.as_local() {
|
||||
self.cx.per_local[NeedsDrop].remove(local);
|
||||
}
|
||||
}
|
||||
|
|
@ -1256,8 +1251,8 @@ 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 box [proj_base @ .., elem] = &place.projection {
|
||||
if *elem == ProjectionElem::Deref {
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if elem == ProjectionElem::Deref {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
reborrow_place = Some(proj_base);
|
||||
|
|
@ -1568,10 +1563,7 @@ 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),
|
||||
projection: box [],
|
||||
} = *place {
|
||||
let needs_drop = if let Some(local) = place.as_local() {
|
||||
if NeedsDrop::in_local(self, local) {
|
||||
Some(self.body.local_decls[local].source_info.span)
|
||||
} else {
|
||||
|
|
@ -1817,16 +1809,17 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
|
|||
}
|
||||
});
|
||||
let terminator = block.terminator_mut();
|
||||
match terminator.kind {
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Drop {
|
||||
location: Place {
|
||||
base: PlaceBase::Local(index),
|
||||
projection: box [],
|
||||
},
|
||||
location,
|
||||
target,
|
||||
..
|
||||
} if promoted_temps.contains(index) => {
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
} => {
|
||||
if let Some(index) = location.as_local() {
|
||||
if promoted_temps.contains(index) {
|
||||
terminator.kind = TerminatorKind::Goto { target: *target };
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ fn check_place(
|
|||
def_id: DefId,
|
||||
body: &Body<'tcx>
|
||||
) -> McfResult {
|
||||
let mut cursor = &*place.projection;
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
match elem {
|
||||
ProjectionElem::Downcast(..) => {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ impl RemoveNoopLandingPads {
|
|||
nop_landing_pads: &BitSet<BasicBlock>,
|
||||
) -> bool {
|
||||
for stmt in &body[bb].statements {
|
||||
match stmt.kind {
|
||||
match &stmt.kind {
|
||||
StatementKind::FakeRead(..) |
|
||||
StatementKind::StorageLive(_) |
|
||||
StatementKind::StorageDead(_) |
|
||||
|
|
@ -41,12 +41,13 @@ impl RemoveNoopLandingPads {
|
|||
// These are all nops in a landing pad
|
||||
}
|
||||
|
||||
StatementKind::Assign(box(Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
}, Rvalue::Use(_))) => {
|
||||
// Writing to a local (e.g., a drop flag) does not
|
||||
// turn a landing pad to a non-nop
|
||||
StatementKind::Assign(box(place, Rvalue::Use(_))) => {
|
||||
if place.as_local().is_some() {
|
||||
// Writing to a local (e.g., a drop flag) does not
|
||||
// turn a landing pad to a non-nop
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
StatementKind::Assign { .. } |
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ fn value_assigned_to_local<'a, 'tcx>(
|
|||
local: Local,
|
||||
) -> Option<&'a mir::Rvalue<'tcx>> {
|
||||
if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
|
||||
if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place {
|
||||
if local == *l {
|
||||
if let Some(l) = place.as_local() {
|
||||
if local == l {
|
||||
return Some(&*rvalue);
|
||||
}
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ impl PeekCall {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
) -> Option<Self> {
|
||||
use mir::{Operand, Place, PlaceBase};
|
||||
use mir::Operand;
|
||||
|
||||
let span = terminator.source_info.span;
|
||||
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
|
||||
|
|
@ -207,14 +207,23 @@ impl PeekCall {
|
|||
|
||||
assert_eq!(args.len(), 1);
|
||||
let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
|
||||
let arg = match args[0] {
|
||||
| Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] })
|
||||
| Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] })
|
||||
=> local,
|
||||
|
||||
let arg = match &args[0] {
|
||||
Operand::Copy(place) | Operand::Move(place) => {
|
||||
if let Some(local) = place.as_local() {
|
||||
local
|
||||
} else {
|
||||
tcx.sess.diagnostic().span_err(
|
||||
span,
|
||||
"dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.diagnostic().span_err(
|
||||
span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
|
||||
span,
|
||||
"dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
|
@ -277,12 +286,11 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> {
|
|||
call: PeekCall,
|
||||
) {
|
||||
warn!("peek_at: place={:?}", place);
|
||||
let local = match place {
|
||||
mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l,
|
||||
_ => {
|
||||
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
|
||||
return;
|
||||
}
|
||||
let local = if let Some(l) = place.as_local() {
|
||||
l
|
||||
} else {
|
||||
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
|
||||
return;
|
||||
};
|
||||
|
||||
if !flow_state.contains(local) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ 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 box [proj_base @ .., elem] = &src_place.projection {
|
||||
if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() {
|
||||
if let ProjectionElem::ConstantIndex{offset: _,
|
||||
min_length: _,
|
||||
from_end: false} = elem {
|
||||
|
|
@ -203,18 +203,17 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
|
|||
if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
|
||||
let items : Vec<_> = items.iter().map(|item| {
|
||||
if let Operand::Move(Place {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: box [],
|
||||
}) = item {
|
||||
let local_use = &visitor.locals_use[*local];
|
||||
let opt_index_and_place =
|
||||
Self::try_get_item_source(local_use, body);
|
||||
// each local should be used twice:
|
||||
// in assign and in aggregate statements
|
||||
if local_use.use_count == 2 && opt_index_and_place.is_some() {
|
||||
let (index, src_place) = opt_index_and_place.unwrap();
|
||||
return Some((local_use, index, src_place));
|
||||
if let Operand::Move(place) = item {
|
||||
if let Some(local) = place.as_local() {
|
||||
let local_use = &visitor.locals_use[local];
|
||||
let opt_index_and_place =
|
||||
Self::try_get_item_source(local_use, body);
|
||||
// each local should be used twice:
|
||||
// in assign and in aggregate statements
|
||||
if local_use.use_count == 2 && opt_index_and_place.is_some() {
|
||||
let (index, src_place) = opt_index_and_place.unwrap();
|
||||
return Some((local_use, index, src_place));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
@ -293,33 +292,27 @@ impl RestoreSubsliceArrayMoveOut {
|
|||
if block.statements.len() > location.statement_index {
|
||||
let statement = &block.statements[location.statement_index];
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
Place {
|
||||
base: PlaceBase::Local(_),
|
||||
projection: box [],
|
||||
},
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: _,
|
||||
projection: box [.., ProjectionElem::ConstantIndex {
|
||||
offset, min_length: _, from_end: false
|
||||
}],
|
||||
})),
|
||||
)
|
||||
box(place, Rvalue::Use(Operand::Move(src_place)))
|
||||
) = &statement.kind {
|
||||
// FIXME remove once we can use slices patterns
|
||||
if let StatementKind::Assign(
|
||||
box(
|
||||
_,
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
if let (Some(_), PlaceRef {
|
||||
base: _,
|
||||
projection: &[.., ProjectionElem::ConstantIndex {
|
||||
offset, min_length: _, from_end: false
|
||||
}],
|
||||
}) = (place.as_local(), src_place.as_ref()) {
|
||||
if let StatementKind::Assign(
|
||||
box(_, Rvalue::Use(Operand::Move(place)))
|
||||
) = &statement.kind {
|
||||
if let PlaceRef {
|
||||
base,
|
||||
projection: box [proj_base @ .., _],
|
||||
})),
|
||||
)
|
||||
) = &statement.kind {
|
||||
return Some((*offset, PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}))
|
||||
projection: &[ref proj_base @ .., _],
|
||||
} = place.as_ref() {
|
||||
return Some((offset, PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
|
|||
where
|
||||
L: HasLocalDecls<'tcx>,
|
||||
{
|
||||
let mut cursor = &*place.projection;
|
||||
while let [proj_base @ .., elem] = cursor {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
cursor = proj_base;
|
||||
|
||||
match elem {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue