use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
use rustc::mir::{
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase,
- Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind,
+ Rvalue, Statement, StatementKind, TerminatorKind,
};
use rustc::ty::{self, TyCtxt};
use rustc::ty::adjustment::{PointerCast};
mod find_use;
+#[derive(Debug)]
pub(in crate::borrow_check) enum BorrowExplanation {
UsedLater(LaterUseKind, Span),
UsedLaterInLoop(LaterUseKind, Span),
Unexplained,
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
pub(in crate::borrow_check) enum LaterUseKind {
TraitCapture,
ClosureCapture,
should_note_order,
} => {
let local_decl = &body.local_decls[dropped_local];
- let (dtor_desc, type_desc) = match local_decl.ty.sty {
+ let (dtor_desc, type_desc) = match local_decl.ty.kind {
// If type is an ADT that implements Drop, then
// simplify output by reporting just the ADT name.
ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => (
Some(Cause::LiveVar(local, location)) => {
let span = body.source_info(location).span;
let spans = self
- .move_spans(&Place::from(local), location)
+ .move_spans(Place::from(local).as_ref(), location)
.or_else(|| self.borrow_spans(span, location));
let borrow_location = location;
let mut should_note_order = false;
if body.local_decls[local].name.is_some() {
if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
- if let Place::Base(PlaceBase::Local(borrowed_local)) = place {
+ if let Place {
+ base: PlaceBase::Local(borrowed_local),
+ projection: box [],
+ } = place {
if body.local_decls[*borrowed_local].name.is_some()
&& local != *borrowed_local
{
region,
);
if let Some(region_name) = region_name {
- let opt_place_desc = self.describe_place(&borrow.borrowed_place);
+ let opt_place_desc =
+ self.describe_place(borrow.borrowed_place.as_ref());
BorrowExplanation::MustBeValidFor {
category,
from_closure,
// Just point to the function, to reduce the chance of overlapping spans.
let function_span = match func {
Operand::Constant(c) => c.span,
- Operand::Copy(Place::Base(PlaceBase::Local(l))) |
- Operand::Move(Place::Base(PlaceBase::Local(l))) => {
+ Operand::Copy(Place {
+ base: PlaceBase::Local(l),
+ projection: 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
// it which simplifies the termination logic.
let mut queue = vec![location];
let mut target = if let Some(&Statement {
- kind: StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _),
+ kind: StatementKind::Assign(box(Place {
+ base: PlaceBase::Local(local),
+ projection: box [],
+ }, _)),
..
}) = stmt
{
debug!("was_captured_by_trait_object: stmt={:?}", stmt);
// The only kind of statement that we care about is assignments...
- if let StatementKind::Assign(place, box rvalue) = &stmt.kind {
- let into = match place {
- Place::Base(PlaceBase::Local(into)) => into,
- Place::Projection(box Projection {
- base: Place::Base(PlaceBase::Local(into)),
- elem: ProjectionElem::Deref,
- }) => into,
- _ => {
+ if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
+ let into = match place.local_or_deref_local() {
+ Some(into) => into,
+ None => {
// Continue at the next location.
queue.push(current_location.successor_within_block());
continue;
// If we see a use, we should check whether it is our data, and if so
// update the place that we're looking for to that new place.
Rvalue::Use(operand) => match operand {
- Operand::Copy(Place::Base(PlaceBase::Local(from)))
- | Operand::Move(Place::Base(PlaceBase::Local(from)))
+ Operand::Copy(Place {
+ base: PlaceBase::Local(from),
+ projection: box [],
+ })
+ | Operand::Move(Place {
+ base: PlaceBase::Local(from),
+ projection: box [],
+ })
if *from == target =>
{
- target = *into;
+ target = into;
}
_ => {}
},
Rvalue::Cast(
CastKind::Pointer(PointerCast::Unsize), operand, ty
) => match operand {
- Operand::Copy(Place::Base(PlaceBase::Local(from)))
- | Operand::Move(Place::Base(PlaceBase::Local(from)))
+ Operand::Copy(Place {
+ base: PlaceBase::Local(from),
+ projection: 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.sty {
+ return match ty.kind {
// `&dyn Trait`
ty::Ref(_, ty, _) if ty.is_trait() => true,
// `Box<dyn Trait>`
debug!("was_captured_by_trait_object: terminator={:?}", terminator);
if let TerminatorKind::Call {
- destination: Some((Place::Base(PlaceBase::Local(dest)), block)),
+ destination: Some((Place {
+ base: PlaceBase::Local(dest),
+ projection: box [],
+ }, block)),
args,
..
} = &terminator.kind
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
- if let Operand::Move(Place::Base(PlaceBase::Local(potential))) = arg {
+ if let Operand::Move(Place {
+ base: PlaceBase::Local(potential),
+ projection: box [],
+ }) = arg {
*potential == target
} else {
false