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:
Santiago Pastorino 2019-10-20 16:09:36 -04:00
parent 270541221f
commit 190802cfca
No known key found for this signature in database
GPG key ID: 88C941CDA1D46432
37 changed files with 709 additions and 822 deletions

View file

@ -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,
}
}

View file

@ -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) {

View file

@ -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"),

View file

@ -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());

View file

@ -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)) => {

View file

@ -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!(

View file

@ -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);
}
}
}
}

View file

@ -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),
};

View file

@ -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;

View file

@ -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"),

View file

@ -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 {

View file

@ -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,

View file

@ -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());
}
}
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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);
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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);
}
}
}

View file

@ -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)

View file

@ -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 {

View file

@ -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] {

View file

@ -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,
}

View file

@ -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,
);

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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,
};
}
}
}
_ => {}

View file

@ -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 };
}
}
}
_ => {}
}

View file

@ -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(..) => {

View file

@ -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 { .. } |

View file

@ -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) {

View file

@ -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,
}))
}
}
}
}
}

View file

@ -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 {