rustfmt: borrow_check/mod.rs
This commit is contained in:
parent
e447b54bc3
commit
39b0e49ebd
1 changed files with 229 additions and 178 deletions
|
|
@ -34,9 +34,9 @@ use dataflow::MoveDataParamEnv;
|
|||
use dataflow::{DataflowAnalysis, DataflowResultsConsumer};
|
||||
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
|
||||
use dataflow::{EverInitializedLvals, MovingOutStatements};
|
||||
use dataflow::{Borrows, BorrowData, ReserveOrActivateIndex};
|
||||
use dataflow::{BorrowData, Borrows, ReserveOrActivateIndex};
|
||||
use dataflow::{ActiveBorrows, Reservations};
|
||||
use dataflow::indexes::{BorrowIndex};
|
||||
use dataflow::indexes::BorrowIndex;
|
||||
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
|
||||
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
|
||||
use util::borrowck_errors::{BorrowckErrors, Origin};
|
||||
|
|
@ -149,9 +149,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
param_env: param_env,
|
||||
};
|
||||
let body_id = match tcx.def_key(def_id).disambiguated_data.data {
|
||||
DefPathData::StructCtor |
|
||||
DefPathData::EnumVariant(_) => None,
|
||||
_ => Some(tcx.hir.body_owned_by(id))
|
||||
DefPathData::StructCtor | DefPathData::EnumVariant(_) => None,
|
||||
_ => Some(tcx.hir.body_owned_by(id)),
|
||||
};
|
||||
|
||||
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
|
||||
|
|
@ -217,8 +216,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
move_data: &mdpe.move_data,
|
||||
param_env: param_env,
|
||||
locals_are_invalidated_at_exit: match tcx.hir.body_owner_kind(id) {
|
||||
hir::BodyOwnerKind::Const |
|
||||
hir::BodyOwnerKind::Static(_) => false,
|
||||
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
|
||||
hir::BodyOwnerKind::Fn => true,
|
||||
},
|
||||
storage_dead_or_drop_error_reported_l: FxHashSet(),
|
||||
|
|
@ -241,18 +239,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
// In practice it is easier to be looser; in particular,
|
||||
// it is okay for the kill-sets to hold activation bits.
|
||||
DebugFormatted::new(&(i.kind(), rs.location(i)))
|
||||
});
|
||||
},
|
||||
);
|
||||
let flow_active_borrows = {
|
||||
let reservations_on_entry = flow_reservations.0.sets.entry_set_state();
|
||||
let reservations = flow_reservations.0.operator;
|
||||
let a = DataflowAnalysis::new_with_entry_sets(mir,
|
||||
&dead_unwinds,
|
||||
Cow::Borrowed(reservations_on_entry),
|
||||
ActiveBorrows::new(reservations));
|
||||
let results = a.run(tcx,
|
||||
id,
|
||||
&attributes,
|
||||
|ab, i| DebugFormatted::new(&(i.kind(), ab.location(i))));
|
||||
let a = DataflowAnalysis::new_with_entry_sets(
|
||||
mir,
|
||||
&dead_unwinds,
|
||||
Cow::Borrowed(reservations_on_entry),
|
||||
ActiveBorrows::new(reservations),
|
||||
);
|
||||
let results = a.run(tcx, id, &attributes, |ab, i| {
|
||||
DebugFormatted::new(&(i.kind(), ab.location(i)))
|
||||
});
|
||||
FlowAtLocation::new(results)
|
||||
};
|
||||
|
||||
|
|
@ -551,9 +551,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||
}
|
||||
});
|
||||
}
|
||||
TerminatorKind::Goto { target: _ } |
|
||||
TerminatorKind::Unreachable |
|
||||
TerminatorKind::FalseEdges { .. } => {
|
||||
TerminatorKind::Goto { target: _ }
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::FalseEdges { .. } => {
|
||||
// no data used, thus irrelevant to borrowck
|
||||
}
|
||||
}
|
||||
|
|
@ -648,13 +648,12 @@ enum LocalMutationIsAllowed {
|
|||
/// We want use of immutable upvars to cause a "write to immutable upvar"
|
||||
/// error, not an "reassignment" error.
|
||||
ExceptUpvars,
|
||||
No
|
||||
No,
|
||||
}
|
||||
|
||||
struct AccessErrorsReported {
|
||||
mutability_error: bool,
|
||||
#[allow(dead_code)]
|
||||
conflict_error: bool
|
||||
#[allow(dead_code)] conflict_error: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -704,9 +703,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
if let Activation(_, borrow_index) = rw {
|
||||
if self.reservation_error_reported.contains(&place_span.0) {
|
||||
debug!("skipping access_place for activation of invalid reservation \
|
||||
place: {:?} borrow_index: {:?}", place_span.0, borrow_index);
|
||||
return AccessErrorsReported { mutability_error: false, conflict_error: true };
|
||||
debug!(
|
||||
"skipping access_place for activation of invalid reservation \
|
||||
place: {:?} borrow_index: {:?}",
|
||||
place_span.0,
|
||||
borrow_index
|
||||
);
|
||||
return AccessErrorsReported {
|
||||
mutability_error: false,
|
||||
conflict_error: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -715,7 +721,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let conflict_error =
|
||||
self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
|
||||
|
||||
AccessErrorsReported { mutability_error, conflict_error }
|
||||
AccessErrorsReported {
|
||||
mutability_error,
|
||||
conflict_error,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_access_for_conflict(
|
||||
|
|
@ -738,22 +747,26 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
//
|
||||
// NOTE: *reservations* do conflict with themselves;
|
||||
// thus aren't injecting unsoundenss w/ this check.)
|
||||
(Activation(_, activating), _) if activating == index.borrow_index() =>
|
||||
{
|
||||
debug!("check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
|
||||
skipping {:?} b/c activation of same borrow_index: {:?}",
|
||||
place_span, sd, rw, (index, borrow), index.borrow_index());
|
||||
(Activation(_, activating), _) if activating == index.borrow_index() => {
|
||||
debug!(
|
||||
"check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
|
||||
skipping {:?} b/c activation of same borrow_index: {:?}",
|
||||
place_span,
|
||||
sd,
|
||||
rw,
|
||||
(index, borrow),
|
||||
index.borrow_index()
|
||||
);
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared) |
|
||||
(Reservation(..), BorrowKind::Shared) => Control::Continue,
|
||||
(Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => {
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Read(kind), BorrowKind::Unique) |
|
||||
(Read(kind), BorrowKind::Mut) => {
|
||||
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if this.tcx.sess.opts.debugging_opts.two_phase_borrows &&
|
||||
index.is_reservation()
|
||||
if this.tcx.sess.opts.debugging_opts.two_phase_borrows && index.is_reservation()
|
||||
{
|
||||
return Control::Continue;
|
||||
}
|
||||
|
|
@ -781,20 +794,25 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Control::Break
|
||||
}
|
||||
|
||||
(Reservation(kind), BorrowKind::Unique) |
|
||||
(Reservation(kind), BorrowKind::Mut) |
|
||||
(Activation(kind, _), _) |
|
||||
(Write(kind), _) => {
|
||||
|
||||
(Reservation(kind), BorrowKind::Unique)
|
||||
| (Reservation(kind), BorrowKind::Mut)
|
||||
| (Activation(kind, _), _)
|
||||
| (Write(kind), _) => {
|
||||
match rw {
|
||||
Reservation(_) => {
|
||||
debug!("recording invalid reservation of \
|
||||
place: {:?}", place_span.0);
|
||||
debug!(
|
||||
"recording invalid reservation of \
|
||||
place: {:?}",
|
||||
place_span.0
|
||||
);
|
||||
this.reservation_error_reported.insert(place_span.0.clone());
|
||||
}
|
||||
Activation(_, activating) => {
|
||||
debug!("observing check_place for activation of \
|
||||
borrow_index: {:?}", activating);
|
||||
debug!(
|
||||
"observing check_place for activation of \
|
||||
borrow_index: {:?}",
|
||||
activating
|
||||
);
|
||||
}
|
||||
Read(..) | Write(..) => {}
|
||||
}
|
||||
|
|
@ -818,8 +836,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
WriteKind::StorageDeadOrDrop => {
|
||||
error_reported = true;
|
||||
this.report_borrowed_value_does_not_live_long_enough(
|
||||
context, borrow, place_span.1,
|
||||
flow_state.borrows.operator());
|
||||
context,
|
||||
borrow,
|
||||
place_span.1,
|
||||
flow_state.borrows.operator(),
|
||||
);
|
||||
}
|
||||
WriteKind::Mutate => {
|
||||
error_reported = true;
|
||||
|
|
@ -917,10 +938,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::Use(ref operand) |
|
||||
Rvalue::Repeat(ref operand, _) |
|
||||
Rvalue::UnaryOp(_ /*un_op*/, ref operand) |
|
||||
Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
|
||||
Rvalue::Use(ref operand)
|
||||
| Rvalue::Repeat(ref operand, _)
|
||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||
| Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
|
||||
self.consume_operand(context, (operand, span), flow_state)
|
||||
}
|
||||
|
||||
|
|
@ -945,8 +966,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) |
|
||||
Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
||||
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
|
||||
| Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
||||
self.consume_operand(context, (operand1, span), flow_state);
|
||||
self.consume_operand(context, (operand2, span), flow_state);
|
||||
}
|
||||
|
|
@ -1015,12 +1036,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
/// Returns whether a borrow of this place is invalidated when the function
|
||||
/// exits
|
||||
fn check_for_invalidation_at_exit(&mut self,
|
||||
context: Context,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
span: Span,
|
||||
flow_state: &Flows<'cx, 'gcx, 'tcx>)
|
||||
{
|
||||
fn check_for_invalidation_at_exit(
|
||||
&mut self,
|
||||
context: Context,
|
||||
borrow: &BorrowData<'tcx>,
|
||||
span: Span,
|
||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||
) {
|
||||
debug!("check_for_invalidation_at_exit({:?})", borrow);
|
||||
let place = &borrow.borrowed_place;
|
||||
let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
|
||||
|
|
@ -1061,11 +1083,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
// FIXME: replace this with a proper borrow_conflicts_with_place when
|
||||
// that is merged.
|
||||
let sd = if might_be_alive {
|
||||
Deep
|
||||
} else {
|
||||
Shallow(None)
|
||||
};
|
||||
let sd = if might_be_alive { Deep } else { Shallow(None) };
|
||||
|
||||
if self.places_conflict(place, root_place, sd) {
|
||||
debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
|
||||
|
|
@ -1075,16 +1093,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
context,
|
||||
borrow,
|
||||
span.end_point(),
|
||||
flow_state.borrows.operator()
|
||||
flow_state.borrows.operator(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_activations(&mut self,
|
||||
location: Location,
|
||||
span: Span,
|
||||
flow_state: &Flows<'cx, 'gcx, 'tcx>)
|
||||
{
|
||||
fn check_activations(
|
||||
&mut self,
|
||||
location: Location,
|
||||
span: Span,
|
||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||
) {
|
||||
if !self.tcx.sess.opts.debugging_opts.two_phase_borrows {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1095,8 +1114,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let domain = flow_state.borrows.operator();
|
||||
let data = domain.borrows();
|
||||
flow_state.borrows.each_gen_bit(|gen| {
|
||||
if gen.is_activation()
|
||||
{
|
||||
if gen.is_activation() {
|
||||
let borrow_index = gen.borrow_index();
|
||||
let borrow = &data[borrow_index];
|
||||
// currently the flow analysis registers
|
||||
|
|
@ -1105,16 +1123,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
// mutable borrow before we check it.
|
||||
match borrow.kind {
|
||||
BorrowKind::Shared => return,
|
||||
BorrowKind::Unique |
|
||||
BorrowKind::Mut => {}
|
||||
BorrowKind::Unique | BorrowKind::Mut => {}
|
||||
}
|
||||
|
||||
self.access_place(ContextKind::Activation.new(location),
|
||||
(&borrow.borrowed_place, span),
|
||||
(Deep, Activation(WriteKind::MutableBorrow(borrow.kind),
|
||||
borrow_index)),
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state);
|
||||
self.access_place(
|
||||
ContextKind::Activation.new(location),
|
||||
(&borrow.borrowed_place, span),
|
||||
(
|
||||
Deep,
|
||||
Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index),
|
||||
),
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
);
|
||||
// We do not need to call `check_if_path_is_moved`
|
||||
// again, as we already called it when we made the
|
||||
// initial reservation.
|
||||
|
|
@ -1135,7 +1156,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
if let Ok(()) = self.is_mutable(place, LocalMutationIsAllowed::No) {
|
||||
return;
|
||||
}
|
||||
debug!("check_if_reassignment_to_immutable_state({:?}) - is an imm local", place);
|
||||
debug!(
|
||||
"check_if_reassignment_to_immutable_state({:?}) - is an imm local",
|
||||
place
|
||||
);
|
||||
|
||||
for i in flow_state.ever_inits.elems_incoming() {
|
||||
let init = self.move_data.inits[i];
|
||||
|
|
@ -1364,14 +1388,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
);
|
||||
let mut error_reported = false;
|
||||
match kind {
|
||||
Reservation(WriteKind::MutableBorrow(BorrowKind::Unique)) |
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Unique)) => {
|
||||
Reservation(WriteKind::MutableBorrow(BorrowKind::Unique))
|
||||
| Write(WriteKind::MutableBorrow(BorrowKind::Unique)) => {
|
||||
if let Err(_place_err) = self.is_mutable(place, LocalMutationIsAllowed::Yes) {
|
||||
span_bug!(span, "&unique borrow for {:?} should not fail", place);
|
||||
}
|
||||
}
|
||||
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut)) |
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut)) => if let Err(place_err) =
|
||||
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut))
|
||||
| Write(WriteKind::MutableBorrow(BorrowKind::Mut)) => if let Err(place_err) =
|
||||
self.is_mutable(place, is_local_mutation_allowed)
|
||||
{
|
||||
error_reported = true;
|
||||
|
|
@ -1393,8 +1417,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
err.emit();
|
||||
},
|
||||
Reservation(WriteKind::Mutate) |
|
||||
Write(WriteKind::Mutate) => {
|
||||
Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
|
||||
if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) {
|
||||
error_reported = true;
|
||||
|
||||
|
|
@ -1415,12 +1438,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
err.emit();
|
||||
}
|
||||
}
|
||||
Reservation(WriteKind::Move) |
|
||||
Reservation(WriteKind::StorageDeadOrDrop) |
|
||||
Reservation(WriteKind::MutableBorrow(BorrowKind::Shared)) |
|
||||
Write(WriteKind::Move) |
|
||||
Write(WriteKind::StorageDeadOrDrop) |
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => {
|
||||
Reservation(WriteKind::Move)
|
||||
| Reservation(WriteKind::StorageDeadOrDrop)
|
||||
| Reservation(WriteKind::MutableBorrow(BorrowKind::Shared))
|
||||
| Write(WriteKind::Move)
|
||||
| Write(WriteKind::StorageDeadOrDrop)
|
||||
| Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => {
|
||||
if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
span,
|
||||
|
|
@ -1435,10 +1458,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
Activation(..) => {} // permission checks are done at Reservation point.
|
||||
|
||||
Read(ReadKind::Borrow(BorrowKind::Unique)) |
|
||||
Read(ReadKind::Borrow(BorrowKind::Mut)) |
|
||||
Read(ReadKind::Borrow(BorrowKind::Shared)) |
|
||||
Read(ReadKind::Copy) => {} // Access authorized
|
||||
Read(ReadKind::Borrow(BorrowKind::Unique))
|
||||
| Read(ReadKind::Borrow(BorrowKind::Mut))
|
||||
| Read(ReadKind::Borrow(BorrowKind::Shared))
|
||||
| Read(ReadKind::Copy) => {} // Access authorized
|
||||
}
|
||||
|
||||
error_reported
|
||||
|
|
@ -1455,8 +1478,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let local = &self.mir.local_decls[local];
|
||||
match local.mutability {
|
||||
Mutability::Not => match is_local_mutation_allowed {
|
||||
LocalMutationIsAllowed::Yes |
|
||||
LocalMutationIsAllowed::ExceptUpvars => Ok(()),
|
||||
LocalMutationIsAllowed::Yes | LocalMutationIsAllowed::ExceptUpvars => {
|
||||
Ok(())
|
||||
}
|
||||
LocalMutationIsAllowed::No => Err(place),
|
||||
},
|
||||
Mutability::Mut => Ok(()),
|
||||
|
|
@ -1481,13 +1505,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
// Mutably borrowed data is mutable, but only if we have a
|
||||
// unique path to the `&mut`
|
||||
hir::MutMutable => {
|
||||
let mode = match
|
||||
self.is_upvar_field_projection(&proj.base)
|
||||
let mode = match self.is_upvar_field_projection(&proj.base)
|
||||
{
|
||||
Some(field) if {
|
||||
self.mir.upvar_decls[field.index()].by_ref
|
||||
} => is_local_mutation_allowed,
|
||||
_ => LocalMutationIsAllowed::Yes
|
||||
Some(field)
|
||||
if {
|
||||
self.mir.upvar_decls[field.index()].by_ref
|
||||
} =>
|
||||
{
|
||||
is_local_mutation_allowed
|
||||
}
|
||||
_ => LocalMutationIsAllowed::Yes,
|
||||
};
|
||||
|
||||
self.is_mutable(&proj.base, mode)
|
||||
|
|
@ -1513,22 +1540,28 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
// All other projections are owned by their base path, so mutable if
|
||||
// base path is mutable
|
||||
ProjectionElem::Field(..) |
|
||||
ProjectionElem::Index(..) |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
ProjectionElem::Subslice { .. } |
|
||||
ProjectionElem::Downcast(..) => {
|
||||
ProjectionElem::Field(..)
|
||||
| ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Downcast(..) => {
|
||||
if let Some(field) = self.is_upvar_field_projection(place) {
|
||||
let decl = &self.mir.upvar_decls[field.index()];
|
||||
debug!("decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
|
||||
decl, is_local_mutation_allowed, place);
|
||||
debug!(
|
||||
"decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
|
||||
decl,
|
||||
is_local_mutation_allowed,
|
||||
place
|
||||
);
|
||||
match (decl.mutability, is_local_mutation_allowed) {
|
||||
(Mutability::Not, LocalMutationIsAllowed::No) |
|
||||
(Mutability::Not, LocalMutationIsAllowed::ExceptUpvars)
|
||||
=> Err(place),
|
||||
(Mutability::Not, LocalMutationIsAllowed::Yes) |
|
||||
(Mutability::Mut, _) =>
|
||||
(Mutability::Not, LocalMutationIsAllowed::No)
|
||||
| (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => {
|
||||
Err(place)
|
||||
}
|
||||
(Mutability::Not, LocalMutationIsAllowed::Yes)
|
||||
| (Mutability::Mut, _) => {
|
||||
self.is_mutable(&proj.base, is_local_mutation_allowed)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.is_mutable(&proj.base, is_local_mutation_allowed)
|
||||
|
|
@ -1593,11 +1626,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
// Given that the bases of `elem1` and `elem2` are always either equal
|
||||
// or disjoint (and have the same type!), return the overlap situation
|
||||
// between `elem1` and `elem2`.
|
||||
fn place_element_conflict(&self,
|
||||
elem1: &Place<'tcx>,
|
||||
elem2: &Place<'tcx>)
|
||||
-> Overlap
|
||||
{
|
||||
fn place_element_conflict(&self, elem1: &Place<'tcx>, elem2: &Place<'tcx>) -> Overlap {
|
||||
match (elem1, elem2) {
|
||||
(Place::Local(l1), Place::Local(l2)) => {
|
||||
if l1 == l2 {
|
||||
|
|
@ -1623,8 +1652,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
}
|
||||
(Place::Local(_), Place::Static(_)) |
|
||||
(Place::Static(_), Place::Local(_)) => {
|
||||
(Place::Local(_), Place::Static(_)) | (Place::Static(_), Place::Local(_)) => {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
|
|
@ -1689,15 +1717,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::Index(..), ProjectionElem::Index(..)) |
|
||||
(ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. }) |
|
||||
(ProjectionElem::Index(..), ProjectionElem::Subslice { .. }) |
|
||||
(ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..)) |
|
||||
(ProjectionElem::ConstantIndex { .. }, ProjectionElem::ConstantIndex { .. }) |
|
||||
(ProjectionElem::ConstantIndex { .. }, ProjectionElem::Subslice { .. }) |
|
||||
(ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) |
|
||||
(ProjectionElem::Subslice { .. }, ProjectionElem::ConstantIndex { .. }) |
|
||||
(ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
|
||||
(ProjectionElem::Index(..), ProjectionElem::Index(..))
|
||||
| (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. })
|
||||
| (ProjectionElem::Index(..), ProjectionElem::Subslice { .. })
|
||||
| (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..))
|
||||
| (
|
||||
ProjectionElem::ConstantIndex { .. },
|
||||
ProjectionElem::ConstantIndex { .. },
|
||||
)
|
||||
| (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Subslice { .. })
|
||||
| (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..))
|
||||
| (ProjectionElem::Subslice { .. }, ProjectionElem::ConstantIndex { .. })
|
||||
| (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
|
||||
// Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
|
||||
// (if the indexes differ) or equal (if they are the same), so this
|
||||
// is the recursive case that gives "equal *or* disjoint" its meaning.
|
||||
|
|
@ -1714,41 +1745,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
|
||||
(ProjectionElem::Deref, _) |
|
||||
(ProjectionElem::Field(..), _) |
|
||||
(ProjectionElem::Index(..), _) |
|
||||
(ProjectionElem::ConstantIndex { .. }, _) |
|
||||
(ProjectionElem::Subslice { .. }, _) |
|
||||
(ProjectionElem::Downcast(..), _) => {
|
||||
bug!("mismatched projections in place_element_conflict: {:?} and {:?}",
|
||||
|
||||
elem1, elem2)
|
||||
}
|
||||
(ProjectionElem::Deref, _)
|
||||
| (ProjectionElem::Field(..), _)
|
||||
| (ProjectionElem::Index(..), _)
|
||||
| (ProjectionElem::ConstantIndex { .. }, _)
|
||||
| (ProjectionElem::Subslice { .. }, _)
|
||||
| (ProjectionElem::Downcast(..), _) => bug!(
|
||||
"mismatched projections in place_element_conflict: {:?} and {:?}",
|
||||
elem1,
|
||||
elem2
|
||||
),
|
||||
}
|
||||
}
|
||||
(Place::Projection(_), _) |
|
||||
(_, Place::Projection(_)) => {
|
||||
bug!("unexpected elements in place_element_conflict: {:?} and {:?}",
|
||||
elem1, elem2)
|
||||
}
|
||||
(Place::Projection(_), _) | (_, Place::Projection(_)) => bug!(
|
||||
"unexpected elements in place_element_conflict: {:?} and {:?}",
|
||||
elem1,
|
||||
elem2
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether an access of kind `access` to `access_place` conflicts with
|
||||
/// a borrow/full access to `borrow_place` (for deep accesses to mutable
|
||||
/// locations, this function is symmetric between `borrow_place` & `access_place`).
|
||||
fn places_conflict(&mut self,
|
||||
borrow_place: &Place<'tcx>,
|
||||
access_place: &Place<'tcx>,
|
||||
access: ShallowOrDeep)
|
||||
-> bool
|
||||
{
|
||||
debug!("places_conflict({:?},{:?},{:?})", borrow_place, access_place, access);
|
||||
fn places_conflict(
|
||||
&mut self,
|
||||
borrow_place: &Place<'tcx>,
|
||||
access_place: &Place<'tcx>,
|
||||
access: ShallowOrDeep,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"places_conflict({:?},{:?},{:?})",
|
||||
borrow_place,
|
||||
access_place,
|
||||
access
|
||||
);
|
||||
|
||||
// Return all the prefixes of `place` in reverse order, including
|
||||
// downcasts.
|
||||
fn place_elements<'a, 'tcx>(place: &'a Place<'tcx>) -> Vec<&'a Place<'tcx>>
|
||||
{
|
||||
fn place_elements<'a, 'tcx>(place: &'a Place<'tcx>) -> Vec<&'a Place<'tcx>> {
|
||||
let mut result = vec![];
|
||||
let mut place = place;
|
||||
loop {
|
||||
|
|
@ -1767,13 +1802,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
let borrow_components = place_elements(borrow_place);
|
||||
let access_components = place_elements(access_place);
|
||||
debug!("places_conflict: components {:?} / {:?}",
|
||||
borrow_components, access_components);
|
||||
debug!(
|
||||
"places_conflict: components {:?} / {:?}",
|
||||
borrow_components,
|
||||
access_components
|
||||
);
|
||||
|
||||
let borrow_components = borrow_components.into_iter()
|
||||
.map(Some).chain(iter::repeat(None));
|
||||
let access_components = access_components.into_iter()
|
||||
.map(Some).chain(iter::repeat(None));
|
||||
let borrow_components = borrow_components
|
||||
.into_iter()
|
||||
.map(Some)
|
||||
.chain(iter::repeat(None));
|
||||
let access_components = access_components
|
||||
.into_iter()
|
||||
.map(Some)
|
||||
.chain(iter::repeat(None));
|
||||
// The borrowck rules for proving disjointness are applied from the "root" of the
|
||||
// borrow forwards, iterating over "similar" projections in lockstep until
|
||||
// we can prove overlap one way or another. Essentially, we treat `Overlap` as
|
||||
|
|
@ -1839,13 +1881,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
let (base, elem) = match borrow_c {
|
||||
Place::Projection(box Projection { base, elem }) => (base, elem),
|
||||
_ => bug!("place has no base?")
|
||||
_ => bug!("place has no base?"),
|
||||
};
|
||||
let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx);
|
||||
|
||||
match (elem, &base_ty.sty, access) {
|
||||
(_, _, Shallow(Some(ArtificialField::Discriminant))) |
|
||||
(_, _, Shallow(Some(ArtificialField::ArrayLength))) => {
|
||||
(_, _, Shallow(Some(ArtificialField::Discriminant)))
|
||||
| (_, _, Shallow(Some(ArtificialField::ArrayLength))) => {
|
||||
// The discriminant and array length are like
|
||||
// additional fields on the type; they do not
|
||||
// overlap any existing data there. Furthermore,
|
||||
|
|
@ -1866,9 +1908,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
debug!("places_conflict: shallow access behind ptr");
|
||||
return false;
|
||||
}
|
||||
(ProjectionElem::Deref, ty::TyRef(_, ty::TypeAndMut {
|
||||
ty: _, mutbl: hir::MutImmutable
|
||||
}), _) => {
|
||||
(
|
||||
ProjectionElem::Deref,
|
||||
ty::TyRef(
|
||||
_,
|
||||
ty::TypeAndMut {
|
||||
ty: _,
|
||||
mutbl: hir::MutImmutable,
|
||||
},
|
||||
),
|
||||
_,
|
||||
) => {
|
||||
// the borrow goes through a dereference of a shared reference.
|
||||
//
|
||||
// I'm not sure why we are tracking these borrows - shared
|
||||
|
|
@ -1878,12 +1928,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
(ProjectionElem::Deref, _, Deep) |
|
||||
(ProjectionElem::Field { .. }, _, _) |
|
||||
(ProjectionElem::Index { ..}, _, _) |
|
||||
(ProjectionElem::ConstantIndex { .. }, _, _) |
|
||||
(ProjectionElem::Subslice { .. }, _, _) |
|
||||
(ProjectionElem::Downcast { .. }, _, _) => {
|
||||
(ProjectionElem::Deref, _, Deep)
|
||||
| (ProjectionElem::Field { .. }, _, _)
|
||||
| (ProjectionElem::Index { .. }, _, _)
|
||||
| (ProjectionElem::ConstantIndex { .. }, _, _)
|
||||
| (ProjectionElem::Subslice { .. }, _, _)
|
||||
| (ProjectionElem::Downcast { .. }, _, _) => {
|
||||
// Recursive case. This can still be disjoint on a
|
||||
// further iteration if this a shallow access and
|
||||
// there's a deref later on, e.g. a borrow
|
||||
|
|
@ -1920,7 +1970,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1963,7 +2012,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
if self.places_conflict(&borrowed.borrowed_place, place, access) {
|
||||
let ctrl = op(self, i, borrowed);
|
||||
if ctrl == Control::Break { return; }
|
||||
if ctrl == Control::Break {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue