1 use crate::borrow_check
::borrow_set
::BorrowSet
;
2 use crate::borrow_check
::location
::LocationTable
;
3 use crate::borrow_check
::{JustWrite, WriteAndRead}
;
4 use crate::borrow_check
::{AccessDepth, Deep, Shallow}
;
5 use crate::borrow_check
::{ReadOrWrite, Activation, Read, Reservation, Write}
;
6 use crate::borrow_check
::{LocalMutationIsAllowed, MutateMode}
;
7 use crate::borrow_check
::ArtificialField
;
8 use crate::borrow_check
::{ReadKind, WriteKind}
;
9 use crate::borrow_check
::nll
::facts
::AllFacts
;
10 use crate::borrow_check
::path_utils
::*;
11 use crate::dataflow
::indexes
::BorrowIndex
;
12 use rustc
::ty
::{self, TyCtxt}
;
13 use rustc
::mir
::visit
::Visitor
;
14 use rustc
::mir
::{BasicBlock, Location, Body, Place, Rvalue}
;
15 use rustc
::mir
::{Statement, StatementKind}
;
16 use rustc
::mir
::TerminatorKind
;
17 use rustc
::mir
::{Operand, BorrowKind}
;
18 use rustc_data_structures
::graph
::dominators
::Dominators
;
20 pub(super) fn generate_invalidates
<'tcx
>(
22 param_env
: ty
::ParamEnv
<'tcx
>,
23 all_facts
: &mut Option
<AllFacts
>,
24 location_table
: &LocationTable
,
26 borrow_set
: &BorrowSet
<'tcx
>,
28 if all_facts
.is_none() {
29 // Nothing to do if we don't have any facts
33 if let Some(all_facts
) = all_facts
{
34 let dominators
= body
.dominators();
35 let mut ig
= InvalidationGenerator
{
48 struct InvalidationGenerator
<'cx
, 'tcx
> {
50 param_env
: ty
::ParamEnv
<'tcx
>,
51 all_facts
: &'cx
mut AllFacts
,
52 location_table
: &'cx LocationTable
,
53 body
: &'cx Body
<'tcx
>,
54 dominators
: Dominators
<BasicBlock
>,
55 borrow_set
: &'cx BorrowSet
<'tcx
>,
58 /// Visits the whole MIR and generates `invalidates()` facts.
59 /// Most of the code implementing this was stolen from `borrow_check/mod.rs`.
60 impl<'cx
, 'tcx
> Visitor
<'tcx
> for InvalidationGenerator
<'cx
, 'tcx
> {
63 statement
: &Statement
<'tcx
>,
66 self.check_activations(location
);
68 match statement
.kind
{
69 StatementKind
::Assign(box(ref lhs
, ref rhs
)) => {
82 StatementKind
::FakeRead(_
, _
) => {
83 // Only relavent for initialized/liveness/safety checks.
85 StatementKind
::SetDiscriminant
{
96 StatementKind
::InlineAsm(ref asm
) => {
97 for (o
, output
) in asm
.asm
.outputs
.iter().zip(asm
.outputs
.iter()) {
99 // FIXME(eddyb) indirect inline asm outputs should
100 // be encoded through MIR place derefs instead.
104 (Deep
, Read(ReadKind
::Copy
)),
105 LocalMutationIsAllowed
::No
,
111 if o
.is_rw { Deep }
else { Shallow(None) }
,
112 if o
.is_rw { WriteAndRead }
else { JustWrite }
,
116 for (_
, input
) in asm
.inputs
.iter() {
117 self.consume_operand(location
, input
);
121 StatementKind
::AscribeUserType(..) |
122 StatementKind
::Retag { .. }
|
123 StatementKind
::StorageLive(..) => {
124 // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
127 StatementKind
::StorageDead(local
) => {
131 (Shallow(None
), Write(WriteKind
::StorageDeadOrDrop
)),
132 LocalMutationIsAllowed
::Yes
,
137 self.super_statement(statement
, location
);
140 fn visit_terminator_kind(
142 kind
: &TerminatorKind
<'tcx
>,
145 self.check_activations(location
);
148 TerminatorKind
::SwitchInt
{
154 self.consume_operand(location
, discr
);
156 TerminatorKind
::Drop
{
157 location
: ref drop_place
,
164 (AccessDepth
::Drop
, Write(WriteKind
::StorageDeadOrDrop
)),
165 LocalMutationIsAllowed
::Yes
,
168 TerminatorKind
::DropAndReplace
{
169 location
: ref drop_place
,
170 value
: ref new_value
,
180 self.consume_operand(
185 TerminatorKind
::Call
{
192 self.consume_operand(location
, func
);
194 self.consume_operand(location
, arg
);
196 if let Some((ref dest
, _
/*bb*/)) = *destination
{
205 TerminatorKind
::Assert
{
212 self.consume_operand(location
, cond
);
213 use rustc
::mir
::interpret
::PanicInfo
;
214 if let PanicInfo
::BoundsCheck { ref len, ref index }
= *msg
{
215 self.consume_operand(location
, len
);
216 self.consume_operand(location
, index
);
219 TerminatorKind
::Yield
{
224 self.consume_operand(location
, value
);
226 // Invalidate all borrows of local places
227 let borrow_set
= self.borrow_set
.clone();
228 let resume
= self.location_table
.start_index(resume
.start_location());
229 for i
in borrow_set
.borrows
.indices() {
230 if borrow_of_local_data(&borrow_set
.borrows
[i
].borrowed_place
) {
231 self.all_facts
.invalidates
.push((resume
, i
));
235 TerminatorKind
::Resume
| TerminatorKind
::Return
| TerminatorKind
::GeneratorDrop
=> {
236 // Invalidate all borrows of local places
237 let borrow_set
= self.borrow_set
.clone();
238 let start
= self.location_table
.start_index(location
);
239 for i
in borrow_set
.borrows
.indices() {
240 if borrow_of_local_data(&borrow_set
.borrows
[i
].borrowed_place
) {
241 self.all_facts
.invalidates
.push((start
, i
));
245 TerminatorKind
::Goto { target: _ }
246 | TerminatorKind
::Abort
247 | TerminatorKind
::Unreachable
248 | TerminatorKind
::FalseEdges
{
252 | TerminatorKind
::FalseUnwind
{
256 // no data used, thus irrelevant to borrowck
260 self.super_terminator_kind(kind
, location
);
264 impl<'cx
, 'tcx
> InvalidationGenerator
<'cx
, 'tcx
> {
265 /// Simulates mutation of a place.
276 (kind
, Write(WriteKind
::Mutate
)),
277 LocalMutationIsAllowed
::ExceptUpvars
,
281 /// Simulates consumption of an operand.
285 operand
: &Operand
<'tcx
>,
288 Operand
::Copy(ref place
) => {
292 (Deep
, Read(ReadKind
::Copy
)),
293 LocalMutationIsAllowed
::No
,
296 Operand
::Move(ref place
) => {
300 (Deep
, Write(WriteKind
::Move
)),
301 LocalMutationIsAllowed
::Yes
,
304 Operand
::Constant(_
) => {}
308 // Simulates consumption of an rvalue
312 rvalue
: &Rvalue
<'tcx
>,
315 Rvalue
::Ref(_
/*rgn*/, bk
, ref place
) => {
316 let access_kind
= match bk
{
317 BorrowKind
::Shallow
=> {
318 (Shallow(Some(ArtificialField
::ShallowBorrow
)), Read(ReadKind
::Borrow(bk
)))
320 BorrowKind
::Shared
=> (Deep
, Read(ReadKind
::Borrow(bk
))),
321 BorrowKind
::Unique
| BorrowKind
::Mut { .. }
=> {
322 let wk
= WriteKind
::MutableBorrow(bk
);
323 if allow_two_phase_borrow(bk
) {
324 (Deep
, Reservation(wk
))
335 LocalMutationIsAllowed
::No
,
339 Rvalue
::Use(ref operand
)
340 | Rvalue
::Repeat(ref operand
, _
)
341 | Rvalue
::UnaryOp(_
/*un_op*/, ref operand
)
342 | Rvalue
::Cast(_
/*cast_kind*/, ref operand
, _
/*ty*/) => {
343 self.consume_operand(location
, operand
)
346 Rvalue
::Len(ref place
) | Rvalue
::Discriminant(ref place
) => {
347 let af
= match *rvalue
{
348 Rvalue
::Len(..) => Some(ArtificialField
::ArrayLength
),
349 Rvalue
::Discriminant(..) => None
,
355 (Shallow(af
), Read(ReadKind
::Copy
)),
356 LocalMutationIsAllowed
::No
,
360 Rvalue
::BinaryOp(_bin_op
, ref operand1
, ref operand2
)
361 | Rvalue
::CheckedBinaryOp(_bin_op
, ref operand1
, ref operand2
) => {
362 self.consume_operand(location
, operand1
);
363 self.consume_operand(location
, operand2
);
366 Rvalue
::NullaryOp(_op
, _ty
) => {
369 Rvalue
::Aggregate(_
, ref operands
) => {
370 for operand
in operands
{
371 self.consume_operand(location
, operand
);
377 /// Simulates an access to a place.
382 kind
: (AccessDepth
, ReadOrWrite
),
383 _is_local_mutation_allowed
: LocalMutationIsAllowed
,
386 // note: not doing check_access_permissions checks because they don't generate invalidates
387 self.check_access_for_conflict(location
, place
, sd
, rw
);
390 fn check_access_for_conflict(
398 "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \
406 let body
= self.body
;
407 let param_env
= self.param_env
;
408 let borrow_set
= self.borrow_set
.clone();
409 let indices
= self.borrow_set
.borrows
.indices();
410 each_borrow_involving_path(
419 |this
, borrow_index
, borrow
| {
420 match (rw
, borrow
.kind
) {
421 // Obviously an activation is compatible with its own
422 // reservation (or even prior activating uses of same
423 // borrow); so don't check if they interfere.
425 // NOTE: *reservations* do conflict with themselves;
426 // thus aren't injecting unsoundenss w/ this check.)
427 (Activation(_
, activating
), _
) if activating
== borrow_index
=> {
428 // Activating a borrow doesn't generate any invalidations, since we
429 // have already taken the reservation
432 (Read(_
), BorrowKind
::Shallow
)
433 | (Read(_
), BorrowKind
::Shared
)
434 | (Read(ReadKind
::Borrow(BorrowKind
::Shallow
)), BorrowKind
::Unique
)
435 | (Read(ReadKind
::Borrow(BorrowKind
::Shallow
)), BorrowKind
::Mut { .. }
) => {
436 // Reads don't invalidate shared or shallow borrows
439 (Read(_
), BorrowKind
::Unique
) | (Read(_
), BorrowKind
::Mut { .. }
) => {
440 // Reading from mere reservations of mutable-borrows is OK.
441 if !is_active(&this
.dominators
, borrow
, location
) {
442 // If the borrow isn't active yet, reads don't invalidate it
443 assert
!(allow_two_phase_borrow(borrow
.kind
));
444 return Control
::Continue
;
447 // Unique and mutable borrows are invalidated by reads from any
449 this
.generate_invalidates(borrow_index
, location
);
453 | (Activation(_
, _
), _
)
455 // unique or mutable borrows are invalidated by writes.
456 // Reservations count as writes since we need to check
457 // that activating the borrow will be OK
458 // FIXME(bob_twinkles) is this actually the right thing to do?
459 this
.generate_invalidates(borrow_index
, location
);
468 /// Generates a new `invalidates(L, B)` fact.
469 fn generate_invalidates(&mut self, b
: BorrowIndex
, l
: Location
) {
470 let lidx
= self.location_table
.start_index(l
);
471 self.all_facts
.invalidates
.push((lidx
, b
));
474 fn check_activations(
478 // Two-phase borrow support: For each activation that is newly
479 // generated at this statement, check if it interferes with
481 for &borrow_index
in self.borrow_set
.activations_at_location(location
) {
482 let borrow
= &self.borrow_set
[borrow_index
];
484 // only mutable borrows should be 2-phase
485 assert
!(match borrow
.kind
{
486 BorrowKind
::Shared
| BorrowKind
::Shallow
=> false,
487 BorrowKind
::Unique
| BorrowKind
::Mut { .. }
=> true,
492 &borrow
.borrowed_place
,
495 Activation(WriteKind
::MutableBorrow(borrow
.kind
), borrow_index
),
497 LocalMutationIsAllowed
::No
,
500 // We do not need to call `check_if_path_or_subpath_is_moved`
501 // again, as we already called it when we made the
502 // initial reservation.