]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/mod.rs
8819908de6ae1ab8d5c4da33aeac624f6829aaef
[rust.git] / src / librustc_mir / borrow_check / mod.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This query borrow-checks the MIR to (further) ensure it is not broken.
12
13 use borrow_check::nll::region_infer::RegionInferenceContext;
14 use rustc::hir;
15 use rustc::hir::Node;
16 use rustc::hir::def_id::DefId;
17 use rustc::hir::map::definitions::DefPathData;
18 use rustc::infer::InferCtxt;
19 use rustc::lint::builtin::UNUSED_MUT;
20 use rustc::middle::borrowck::SignalledError;
21 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
22 use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place};
23 use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
24 use rustc::mir::{Terminator, TerminatorKind};
25 use rustc::ty::query::Providers;
26 use rustc::ty::{self, TyCtxt};
27
28 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level};
29 use rustc_data_structures::bit_set::BitSet;
30 use rustc_data_structures::fx::FxHashSet;
31 use rustc_data_structures::graph::dominators::Dominators;
32 use smallvec::SmallVec;
33
34 use std::rc::Rc;
35 use std::collections::BTreeMap;
36
37 use syntax_pos::Span;
38
39 use dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex};
40 use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError};
41 use dataflow::Borrows;
42 use dataflow::DataflowResultsConsumer;
43 use dataflow::FlowAtLocation;
44 use dataflow::MoveDataParamEnv;
45 use dataflow::{do_dataflow, DebugFormatted};
46 use dataflow::EverInitializedPlaces;
47 use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
48 use util::borrowck_errors::{BorrowckErrors, Origin};
49
50 use self::borrow_set::{BorrowData, BorrowSet};
51 use self::flows::Flows;
52 use self::location::LocationTable;
53 use self::prefixes::PrefixSet;
54 use self::MutateMode::{JustWrite, WriteAndRead};
55 use self::mutability_errors::AccessKind;
56
57 use self::path_utils::*;
58
59 crate mod borrow_set;
60 mod error_reporting;
61 mod flows;
62 mod location;
63 mod move_errors;
64 mod mutability_errors;
65 mod path_utils;
66 crate mod place_ext;
67 mod places_conflict;
68 mod prefixes;
69 mod used_muts;
70
71 pub(crate) mod nll;
72
73 pub fn provide(providers: &mut Providers) {
74     *providers = Providers {
75         mir_borrowck,
76         ..*providers
77     };
78 }
79
80 fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowCheckResult<'tcx> {
81     let input_mir = tcx.mir_validated(def_id);
82     debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
83
84     let mut return_early;
85
86     // Return early if we are not supposed to use MIR borrow checker for this function.
87     return_early = !tcx.has_attr(def_id, "rustc_mir") && !tcx.use_mir_borrowck();
88
89     if tcx.is_struct_constructor(def_id) {
90         // We are not borrow checking the automatically generated struct constructors
91         // because we want to accept structs such as this (taken from the `linked-hash-map`
92         // crate):
93         // ```rust
94         // struct Qey<Q: ?Sized>(Q);
95         // ```
96         // MIR of this struct constructor looks something like this:
97         // ```rust
98         // fn Qey(_1: Q) -> Qey<Q>{
99         //     let mut _0: Qey<Q>;                  // return place
100         //
101         //     bb0: {
102         //         (_0.0: Q) = move _1;             // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
103         //         return;                          // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
104         //     }
105         // }
106         // ```
107         // The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
108         // of statically known size, which is not known to be true because of the
109         // `Q: ?Sized` constraint. However, it is true because the constructor can be
110         // called only when `Q` is of statically known size.
111         return_early = true;
112     }
113
114     if return_early {
115         return BorrowCheckResult {
116             closure_requirements: None,
117             used_mut_upvars: SmallVec::new(),
118         };
119     }
120
121     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
122         let input_mir: &Mir = &input_mir.borrow();
123         do_mir_borrowck(&infcx, input_mir, def_id)
124     });
125     debug!("mir_borrowck done");
126
127     opt_closure_req
128 }
129
130 fn do_mir_borrowck<'a, 'gcx, 'tcx>(
131     infcx: &InferCtxt<'a, 'gcx, 'tcx>,
132     input_mir: &Mir<'gcx>,
133     def_id: DefId,
134 ) -> BorrowCheckResult<'gcx> {
135     debug!("do_mir_borrowck(def_id = {:?})", def_id);
136
137     let tcx = infcx.tcx;
138     let attributes = tcx.get_attrs(def_id);
139     let param_env = tcx.param_env(def_id);
140     let id = tcx
141         .hir
142         .as_local_node_id(def_id)
143         .expect("do_mir_borrowck: non-local DefId");
144
145     // Replace all regions with fresh inference variables. This
146     // requires first making our own copy of the MIR. This copy will
147     // be modified (in place) to contain non-lexical lifetimes. It
148     // will have a lifetime tied to the inference context.
149     let mut mir: Mir<'tcx> = input_mir.clone();
150     let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir);
151     let mir = &mir; // no further changes
152     let location_table = &LocationTable::new(mir);
153
154     let mut errors_buffer = Vec::new();
155     let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
156         match MoveData::gather_moves(mir, tcx) {
157             Ok(move_data) => (move_data, None),
158             Err((move_data, move_errors)) => (move_data, Some(move_errors)),
159         };
160
161     let mdpe = MoveDataParamEnv {
162         move_data: move_data,
163         param_env: param_env,
164     };
165     let body_id = match tcx.def_key(def_id).disambiguated_data.data {
166         DefPathData::StructCtor | DefPathData::EnumVariant(_) => None,
167         _ => Some(tcx.hir.body_owned_by(id)),
168     };
169
170     let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
171     let mut flow_inits = FlowAtLocation::new(do_dataflow(
172         tcx,
173         mir,
174         id,
175         &attributes,
176         &dead_unwinds,
177         MaybeInitializedPlaces::new(tcx, mir, &mdpe),
178         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
179     ));
180
181     let locals_are_invalidated_at_exit = match tcx.hir.body_owner_kind(id) {
182             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
183             hir::BodyOwnerKind::Fn => true,
184     };
185     let borrow_set = Rc::new(BorrowSet::build(
186             tcx, mir, locals_are_invalidated_at_exit, &mdpe.move_data));
187
188     // If we are in non-lexical mode, compute the non-lexical lifetimes.
189     let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
190         infcx,
191         def_id,
192         free_regions,
193         mir,
194         location_table,
195         param_env,
196         &mut flow_inits,
197         &mdpe.move_data,
198         &borrow_set,
199         &mut errors_buffer,
200     );
201
202     // The various `flow_*` structures can be large. We drop `flow_inits` here
203     // so it doesn't overlap with the others below. This reduces peak memory
204     // usage significantly on some benchmarks.
205     drop(flow_inits);
206
207     let regioncx = Rc::new(regioncx);
208
209     let flow_borrows = FlowAtLocation::new(do_dataflow(
210         tcx,
211         mir,
212         id,
213         &attributes,
214         &dead_unwinds,
215         Borrows::new(tcx, mir, regioncx.clone(), def_id, body_id, &borrow_set),
216         |rs, i| DebugFormatted::new(&rs.location(i)),
217     ));
218     let flow_uninits = FlowAtLocation::new(do_dataflow(
219         tcx,
220         mir,
221         id,
222         &attributes,
223         &dead_unwinds,
224         MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
225         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
226     ));
227     let flow_ever_inits = FlowAtLocation::new(do_dataflow(
228         tcx,
229         mir,
230         id,
231         &attributes,
232         &dead_unwinds,
233         EverInitializedPlaces::new(tcx, mir, &mdpe),
234         |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
235     ));
236
237     let movable_generator = match tcx.hir.get(id) {
238         Node::Expr(&hir::Expr {
239             node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)),
240             ..
241         }) => false,
242         _ => true,
243     };
244
245     let dominators = mir.dominators();
246
247     let mut mbcx = MirBorrowckCtxt {
248         infcx,
249         mir,
250         mir_def_id: def_id,
251         move_data: &mdpe.move_data,
252         location_table,
253         movable_generator,
254         locals_are_invalidated_at_exit,
255         access_place_error_reported: Default::default(),
256         reservation_error_reported: Default::default(),
257         move_error_reported: BTreeMap::new(),
258         uninitialized_error_reported: Default::default(),
259         errors_buffer,
260         nonlexical_regioncx: regioncx,
261         used_mut: Default::default(),
262         used_mut_upvars: SmallVec::new(),
263         borrow_set,
264         dominators,
265     };
266
267     let mut state = Flows::new(
268         flow_borrows,
269         flow_uninits,
270         flow_ever_inits,
271         polonius_output,
272     );
273
274     if let Some(errors) = move_errors {
275         mbcx.report_move_errors(errors);
276     }
277     mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
278
279     // For each non-user used mutable variable, check if it's been assigned from
280     // a user-declared local. If so, then put that local into the used_mut set.
281     // Note that this set is expected to be small - only upvars from closures
282     // would have a chance of erroneously adding non-user-defined mutable vars
283     // to the set.
284     let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter()
285         .filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none())
286         .cloned()
287         .collect();
288     // For the remaining unused locals that are marked as mutable, we avoid linting any that
289     // were never initialized. These locals may have been removed as unreachable code; or will be
290     // linted as unused variables.
291     let unused_mut_locals = mbcx.mir.mut_vars_iter()
292         .filter(|local| !mbcx.used_mut.contains(local))
293         .collect();
294     mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
295
296     debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
297     let used_mut = mbcx.used_mut;
298     for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
299         if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
300             let local_decl = &mbcx.mir.local_decls[local];
301
302             // Skip implicit `self` argument for closures
303             if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) {
304                 continue;
305             }
306
307             // Skip over locals that begin with an underscore or have no name
308             match local_decl.name {
309                 Some(name) => if name.as_str().starts_with("_") {
310                     continue;
311                 },
312                 None => continue,
313             }
314
315             let span = local_decl.source_info.span;
316             if span.compiler_desugaring_kind().is_some() {
317                 // If the `mut` arises as part of a desugaring, we should ignore it.
318                 continue;
319             }
320
321             let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
322             tcx.struct_span_lint_node(
323                 UNUSED_MUT,
324                 vsi[local_decl.source_info.scope].lint_root,
325                 span,
326                 "variable does not need to be mutable",
327             )
328             .span_suggestion_short_with_applicability(
329                 mut_span,
330                 "remove this `mut`",
331                 String::new(),
332                 Applicability::MachineApplicable,
333             )
334             .emit();
335         }
336     }
337
338     // Buffer any move errors that we collected and de-duplicated.
339     for (_, (_, diag)) in mbcx.move_error_reported {
340         diag.buffer(&mut mbcx.errors_buffer);
341     }
342
343     if !mbcx.errors_buffer.is_empty() {
344         mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span());
345
346         if tcx.migrate_borrowck() {
347             // When borrowck=migrate, check if AST-borrowck would
348             // error on the given code.
349
350             // rust-lang/rust#55492: loop over parents to ensure that
351             // errors that AST-borrowck only detects in some parent of
352             // a closure still allows NLL to signal an error.
353             let mut curr_def_id = def_id;
354             let signalled_any_error = loop {
355                 match tcx.borrowck(curr_def_id).signalled_any_error {
356                     SignalledError::NoErrorsSeen => {
357                         // keep traversing (and borrow-checking) parents
358                     }
359                     SignalledError::SawSomeError => {
360                         // stop search here
361                         break SignalledError::SawSomeError;
362                     }
363                 }
364
365                 if tcx.is_closure(curr_def_id) {
366                     curr_def_id = tcx.parent_def_id(curr_def_id)
367                         .expect("a closure must have a parent_def_id");
368                 } else {
369                     break SignalledError::NoErrorsSeen;
370                 }
371             };
372
373             match signalled_any_error {
374                 SignalledError::NoErrorsSeen => {
375                     // if AST-borrowck signalled no errors, then
376                     // downgrade all the buffered MIR-borrowck errors
377                     // to warnings.
378                     for err in &mut mbcx.errors_buffer {
379                         if err.is_error() {
380                             err.level = Level::Warning;
381                             err.warn("This error has been downgraded to a warning \
382                                       for backwards compatibility with previous releases.\n\
383                                       It represents potential unsoundness in your code.\n\
384                                       This warning will become a hard error in the future.");
385                         }
386                     }
387                 }
388                 SignalledError::SawSomeError => {
389                     // if AST-borrowck signalled a (cancelled) error,
390                     // then we will just emit the buffered
391                     // MIR-borrowck errors as normal.
392                 }
393             }
394         }
395
396         for diag in mbcx.errors_buffer.drain(..) {
397             DiagnosticBuilder::new_diagnostic(mbcx.infcx.tcx.sess.diagnostic(), diag).emit();
398         }
399     }
400
401     let result = BorrowCheckResult {
402         closure_requirements: opt_closure_req,
403         used_mut_upvars: mbcx.used_mut_upvars,
404     };
405
406     debug!("do_mir_borrowck: result = {:#?}", result);
407
408     result
409 }
410
411 pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
412     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
413     mir: &'cx Mir<'tcx>,
414     mir_def_id: DefId,
415     move_data: &'cx MoveData<'tcx>,
416
417     /// Map from MIR `Location` to `LocationIndex`; created
418     /// when MIR borrowck begins.
419     location_table: &'cx LocationTable,
420
421     movable_generator: bool,
422     /// This keeps track of whether local variables are free-ed when the function
423     /// exits even without a `StorageDead`, which appears to be the case for
424     /// constants.
425     ///
426     /// I'm not sure this is the right approach - @eddyb could you try and
427     /// figure this out?
428     locals_are_invalidated_at_exit: bool,
429     /// This field keeps track of when borrow errors are reported in the access_place function
430     /// so that there is no duplicate reporting. This field cannot also be used for the conflicting
431     /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
432     /// of the `Span` type (while required to mute some errors) stops the muting of the reservation
433     /// errors.
434     access_place_error_reported: FxHashSet<(Place<'tcx>, Span)>,
435     /// This field keeps track of when borrow conflict errors are reported
436     /// for reservations, so that we don't report seemingly duplicate
437     /// errors for corresponding activations
438     ///
439     /// FIXME: Ideally this would be a set of BorrowIndex, not Places,
440     /// but it is currently inconvenient to track down the BorrowIndex
441     /// at the time we detect and report a reservation error.
442     reservation_error_reported: FxHashSet<Place<'tcx>>,
443     /// This field keeps track of move errors that are to be reported for given move indicies.
444     ///
445     /// There are situations where many errors can be reported for a single move out (see #53807)
446     /// and we want only the best of those errors.
447     ///
448     /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
449     /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
450     /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
451     /// all move errors have been reported, any diagnostics in this map are added to the buffer
452     /// to be emitted.
453     ///
454     /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
455     /// when errors in the map are being re-added to the error buffer so that errors with the
456     /// same primary span come out in a consistent order.
457     move_error_reported: BTreeMap<Vec<MoveOutIndex>, (Place<'tcx>, DiagnosticBuilder<'cx>)>,
458     /// This field keeps track of errors reported in the checking of uninitialized variables,
459     /// so that we don't report seemingly duplicate errors.
460     uninitialized_error_reported: FxHashSet<Place<'tcx>>,
461     /// Errors to be reported buffer
462     errors_buffer: Vec<Diagnostic>,
463     /// This field keeps track of all the local variables that are declared mut and are mutated.
464     /// Used for the warning issued by an unused mutable local variable.
465     used_mut: FxHashSet<Local>,
466     /// If the function we're checking is a closure, then we'll need to report back the list of
467     /// mutable upvars that have been used. This field keeps track of them.
468     used_mut_upvars: SmallVec<[Field; 8]>,
469     /// Non-lexical region inference context, if NLL is enabled.  This
470     /// contains the results from region inference and lets us e.g.
471     /// find out which CFG points are contained in each borrow region.
472     nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
473
474     /// The set of borrows extracted from the MIR
475     borrow_set: Rc<BorrowSet<'tcx>>,
476
477     /// Dominators for MIR
478     dominators: Dominators<BasicBlock>,
479 }
480
481 // Check that:
482 // 1. assignments are always made to mutable locations (FIXME: does that still really go here?)
483 // 2. loans made in overlapping scopes do not conflict
484 // 3. assignments do not affect things loaned out as immutable
485 // 4. moves do not affect things loaned out in any way
486 impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
487     type FlowState = Flows<'cx, 'gcx, 'tcx>;
488
489     fn mir(&self) -> &'cx Mir<'tcx> {
490         self.mir
491     }
492
493     fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
494         debug!("MirBorrowckCtxt::process_block({:?}): {}", bb, flow_state);
495     }
496
497     fn visit_statement_entry(
498         &mut self,
499         location: Location,
500         stmt: &Statement<'tcx>,
501         flow_state: &Self::FlowState,
502     ) {
503         debug!(
504             "MirBorrowckCtxt::process_statement({:?}, {:?}): {}",
505             location, stmt, flow_state
506         );
507         let span = stmt.source_info.span;
508
509         self.check_activations(location, span, flow_state);
510
511         match stmt.kind {
512             StatementKind::Assign(ref lhs, ref rhs) => {
513                 self.consume_rvalue(
514                     ContextKind::AssignRhs.new(location),
515                     (rhs, span),
516                     location,
517                     flow_state,
518                 );
519
520                 self.mutate_place(
521                     ContextKind::AssignLhs.new(location),
522                     (lhs, span),
523                     Shallow(None),
524                     JustWrite,
525                     flow_state,
526                 );
527             }
528             StatementKind::FakeRead(_, ref place) => {
529                 // Read for match doesn't access any memory and is used to
530                 // assert that a place is safe and live. So we don't have to
531                 // do any checks here.
532                 //
533                 // FIXME: Remove check that the place is initialized. This is
534                 // needed for now because matches don't have never patterns yet.
535                 // So this is the only place we prevent
536                 //      let x: !;
537                 //      match x {};
538                 // from compiling.
539                 self.check_if_path_or_subpath_is_moved(
540                     ContextKind::FakeRead.new(location),
541                     InitializationRequiringAction::Use,
542                     (place, span),
543                     flow_state,
544                 );
545             }
546             StatementKind::SetDiscriminant {
547                 ref place,
548                 variant_index: _,
549             } => {
550                 self.mutate_place(
551                     ContextKind::SetDiscrim.new(location),
552                     (place, span),
553                     Shallow(Some(ArtificialField::Discriminant)),
554                     JustWrite,
555                     flow_state,
556                 );
557             }
558             StatementKind::InlineAsm {
559                 ref asm,
560                 ref outputs,
561                 ref inputs,
562             } => {
563                 let context = ContextKind::InlineAsm.new(location);
564                 for (o, output) in asm.outputs.iter().zip(outputs.iter()) {
565                     if o.is_indirect {
566                         // FIXME(eddyb) indirect inline asm outputs should
567                         // be encoeded through MIR place derefs instead.
568                         self.access_place(
569                             context,
570                             (output, o.span),
571                             (Deep, Read(ReadKind::Copy)),
572                             LocalMutationIsAllowed::No,
573                             flow_state,
574                         );
575                         self.check_if_path_or_subpath_is_moved(
576                             context,
577                             InitializationRequiringAction::Use,
578                             (output, o.span),
579                             flow_state,
580                         );
581                     } else {
582                         self.mutate_place(
583                             context,
584                             (output, o.span),
585                             if o.is_rw { Deep } else { Shallow(None) },
586                             if o.is_rw { WriteAndRead } else { JustWrite },
587                             flow_state,
588                         );
589                     }
590                 }
591                 for (_, input) in inputs.iter() {
592                     self.consume_operand(context, (input, span), flow_state);
593                 }
594             }
595             StatementKind::Nop
596             | StatementKind::AscribeUserType(..)
597             | StatementKind::Retag { .. }
598             | StatementKind::EscapeToRaw { .. }
599             | StatementKind::StorageLive(..) => {
600                 // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
601                 // to borrow check.
602             }
603             StatementKind::StorageDead(local) => {
604                 self.access_place(
605                     ContextKind::StorageDead.new(location),
606                     (&Place::Local(local), span),
607                     (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
608                     LocalMutationIsAllowed::Yes,
609                     flow_state,
610                 );
611             }
612         }
613     }
614
615     fn visit_terminator_entry(
616         &mut self,
617         location: Location,
618         term: &Terminator<'tcx>,
619         flow_state: &Self::FlowState,
620     ) {
621         let loc = location;
622         debug!(
623             "MirBorrowckCtxt::process_terminator({:?}, {:?}): {}",
624             location, term, flow_state
625         );
626         let span = term.source_info.span;
627
628         self.check_activations(location, span, flow_state);
629
630         match term.kind {
631             TerminatorKind::SwitchInt {
632                 ref discr,
633                 switch_ty: _,
634                 values: _,
635                 targets: _,
636             } => {
637                 self.consume_operand(ContextKind::SwitchInt.new(loc), (discr, span), flow_state);
638             }
639             TerminatorKind::Drop {
640                 location: ref drop_place,
641                 target: _,
642                 unwind: _,
643             } => {
644                 let gcx = self.infcx.tcx.global_tcx();
645
646                 // Compute the type with accurate region information.
647                 let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx);
648
649                 // Erase the regions.
650                 let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty)
651                     .to_ty(self.infcx.tcx);
652
653                 // "Lift" into the gcx -- once regions are erased, this type should be in the
654                 // global arenas; this "lift" operation basically just asserts that is true, but
655                 // that is useful later.
656                 let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
657
658                 debug!("visit_terminator_drop \
659                         loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
660                        loc, term, drop_place, drop_place_ty, span);
661
662                 self.access_place(
663                     ContextKind::Drop.new(loc),
664                     (drop_place, span),
665                     (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
666                     LocalMutationIsAllowed::Yes,
667                     flow_state,
668                 );
669             }
670             TerminatorKind::DropAndReplace {
671                 location: ref drop_place,
672                 value: ref new_value,
673                 target: _,
674                 unwind: _,
675             } => {
676                 self.mutate_place(
677                     ContextKind::DropAndReplace.new(loc),
678                     (drop_place, span),
679                     Deep,
680                     JustWrite,
681                     flow_state,
682                 );
683                 self.consume_operand(
684                     ContextKind::DropAndReplace.new(loc),
685                     (new_value, span),
686                     flow_state,
687                 );
688             }
689             TerminatorKind::Call {
690                 ref func,
691                 ref args,
692                 ref destination,
693                 cleanup: _,
694                 from_hir_call: _,
695             } => {
696                 self.consume_operand(ContextKind::CallOperator.new(loc), (func, span), flow_state);
697                 for arg in args {
698                     self.consume_operand(
699                         ContextKind::CallOperand.new(loc),
700                         (arg, span),
701                         flow_state,
702                     );
703                 }
704                 if let Some((ref dest, _ /*bb*/)) = *destination {
705                     self.mutate_place(
706                         ContextKind::CallDest.new(loc),
707                         (dest, span),
708                         Deep,
709                         JustWrite,
710                         flow_state,
711                     );
712                 }
713             }
714             TerminatorKind::Assert {
715                 ref cond,
716                 expected: _,
717                 ref msg,
718                 target: _,
719                 cleanup: _,
720             } => {
721                 self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
722                 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
723                 if let BoundsCheck { ref len, ref index } = *msg {
724                     self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
725                     self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state);
726                 }
727             }
728
729             TerminatorKind::Yield {
730                 ref value,
731                 resume: _,
732                 drop: _,
733             } => {
734                 self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state);
735
736                 if self.movable_generator {
737                     // Look for any active borrows to locals
738                     let borrow_set = self.borrow_set.clone();
739                     flow_state.with_outgoing_borrows(|borrows| {
740                         for i in borrows {
741                             let borrow = &borrow_set[i];
742                             self.check_for_local_borrow(borrow, span);
743                         }
744                     });
745                 }
746             }
747
748             TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
749                 // Returning from the function implicitly kills storage for all locals and statics.
750                 // Often, the storage will already have been killed by an explicit
751                 // StorageDead, but we don't always emit those (notably on unwind paths),
752                 // so this "extra check" serves as a kind of backup.
753                 let borrow_set = self.borrow_set.clone();
754                 flow_state.with_outgoing_borrows(|borrows| {
755                     for i in borrows {
756                         let borrow = &borrow_set[i];
757                         let context = ContextKind::StorageDead.new(loc);
758                         self.check_for_invalidation_at_exit(context, borrow, span);
759                     }
760                 });
761             }
762             TerminatorKind::Goto { target: _ }
763             | TerminatorKind::Abort
764             | TerminatorKind::Unreachable
765             | TerminatorKind::FalseEdges {
766                 real_target: _,
767                 imaginary_targets: _,
768             }
769             | TerminatorKind::FalseUnwind {
770                 real_target: _,
771                 unwind: _,
772             } => {
773                 // no data used, thus irrelevant to borrowck
774             }
775         }
776     }
777 }
778
779 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
780 enum MutateMode {
781     JustWrite,
782     WriteAndRead,
783 }
784
785 use self::ReadOrWrite::{Activation, Read, Reservation, Write};
786 use self::AccessDepth::{Deep, Shallow};
787
788 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
789 enum ArtificialField {
790     Discriminant,
791     ArrayLength,
792     ShallowBorrow,
793 }
794
795 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
796 enum AccessDepth {
797     /// From the RFC: "A *shallow* access means that the immediate
798     /// fields reached at P are accessed, but references or pointers
799     /// found within are not dereferenced. Right now, the only access
800     /// that is shallow is an assignment like `x = ...;`, which would
801     /// be a *shallow write* of `x`."
802     Shallow(Option<ArtificialField>),
803
804     /// From the RFC: "A *deep* access means that all data reachable
805     /// through the given place may be invalidated or accesses by
806     /// this action."
807     Deep,
808
809     /// Access is Deep only when there is a Drop implementation that
810     /// can reach the data behind the reference.
811     Drop,
812 }
813
814 /// Kind of access to a value: read or write
815 /// (For informational purposes only)
816 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
817 enum ReadOrWrite {
818     /// From the RFC: "A *read* means that the existing data may be
819     /// read, but will not be changed."
820     Read(ReadKind),
821
822     /// From the RFC: "A *write* means that the data may be mutated to
823     /// new values or otherwise invalidated (for example, it could be
824     /// de-initialized, as in a move operation).
825     Write(WriteKind),
826
827     /// For two-phase borrows, we distinguish a reservation (which is treated
828     /// like a Read) from an activation (which is treated like a write), and
829     /// each of those is furthermore distinguished from Reads/Writes above.
830     Reservation(WriteKind),
831     Activation(WriteKind, BorrowIndex),
832 }
833
834 /// Kind of read access to a value
835 /// (For informational purposes only)
836 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
837 enum ReadKind {
838     Borrow(BorrowKind),
839     Copy,
840 }
841
842 /// Kind of write access to a value
843 /// (For informational purposes only)
844 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
845 enum WriteKind {
846     StorageDeadOrDrop,
847     MutableBorrow(BorrowKind),
848     Mutate,
849     Move,
850 }
851
852 /// When checking permissions for a place access, this flag is used to indicate that an immutable
853 /// local place can be mutated.
854 ///
855 /// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
856 /// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`
857 /// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
858 ///   `is_declared_mutable()`
859 /// - Take flow state into consideration in `is_assignable()` for local variables
860 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
861 enum LocalMutationIsAllowed {
862     Yes,
863     /// We want use of immutable upvars to cause a "write to immutable upvar"
864     /// error, not an "reassignment" error.
865     ExceptUpvars,
866     No,
867 }
868
869 #[derive(Copy, Clone, Debug)]
870 enum InitializationRequiringAction {
871     Update,
872     Borrow,
873     MatchOn,
874     Use,
875     Assignment,
876     PartialAssignment,
877 }
878
879 struct RootPlace<'d, 'tcx: 'd> {
880     place: &'d Place<'tcx>,
881     is_local_mutation_allowed: LocalMutationIsAllowed,
882 }
883
884 impl InitializationRequiringAction {
885     fn as_noun(self) -> &'static str {
886         match self {
887             InitializationRequiringAction::Update => "update",
888             InitializationRequiringAction::Borrow => "borrow",
889             InitializationRequiringAction::MatchOn => "use", // no good noun
890             InitializationRequiringAction::Use => "use",
891             InitializationRequiringAction::Assignment => "assign",
892             InitializationRequiringAction::PartialAssignment => "assign to part",
893         }
894     }
895
896     fn as_verb_in_past_tense(self) -> &'static str {
897         match self {
898             InitializationRequiringAction::Update => "updated",
899             InitializationRequiringAction::Borrow => "borrowed",
900             InitializationRequiringAction::MatchOn => "matched on",
901             InitializationRequiringAction::Use => "used",
902             InitializationRequiringAction::Assignment => "assigned",
903             InitializationRequiringAction::PartialAssignment => "partially assigned",
904         }
905     }
906 }
907
908 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
909     /// Checks an access to the given place to see if it is allowed. Examines the set of borrows
910     /// that are in scope, as well as which paths have been initialized, to ensure that (a) the
911     /// place is initialized and (b) it is not borrowed in some way that would prevent this
912     /// access.
913     ///
914     /// Returns true if an error is reported, false otherwise.
915     fn access_place(
916         &mut self,
917         context: Context,
918         place_span: (&Place<'tcx>, Span),
919         kind: (AccessDepth, ReadOrWrite),
920         is_local_mutation_allowed: LocalMutationIsAllowed,
921         flow_state: &Flows<'cx, 'gcx, 'tcx>,
922     ) {
923         let (sd, rw) = kind;
924
925         if let Activation(_, borrow_index) = rw {
926             if self.reservation_error_reported.contains(&place_span.0) {
927                 debug!(
928                     "skipping access_place for activation of invalid reservation \
929                      place: {:?} borrow_index: {:?}",
930                     place_span.0, borrow_index
931                 );
932                 return;
933             }
934         }
935
936         // Check is_empty() first because it's the common case, and doing that
937         // way we avoid the clone() call.
938         if !self.access_place_error_reported.is_empty() &&
939            self
940             .access_place_error_reported
941             .contains(&(place_span.0.clone(), place_span.1))
942         {
943             debug!(
944                 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
945                 place_span, kind
946             );
947             return;
948         }
949
950         let mutability_error =
951             self.check_access_permissions(
952                 place_span,
953                 rw,
954                 is_local_mutation_allowed,
955                 flow_state,
956                 context.loc,
957             );
958         let conflict_error =
959             self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
960
961         if conflict_error || mutability_error {
962             debug!(
963                 "access_place: logging error place_span=`{:?}` kind=`{:?}`",
964                 place_span, kind
965             );
966             self.access_place_error_reported
967                 .insert((place_span.0.clone(), place_span.1));
968         }
969     }
970
971     fn check_access_for_conflict(
972         &mut self,
973         context: Context,
974         place_span: (&Place<'tcx>, Span),
975         sd: AccessDepth,
976         rw: ReadOrWrite,
977         flow_state: &Flows<'cx, 'gcx, 'tcx>,
978     ) -> bool {
979         debug!(
980             "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
981             context, place_span, sd, rw,
982         );
983
984         let mut error_reported = false;
985         let tcx = self.infcx.tcx;
986         let mir = self.mir;
987         let location = self.location_table.start_index(context.loc);
988         let borrow_set = self.borrow_set.clone();
989         each_borrow_involving_path(
990             self,
991             tcx,
992             mir,
993             context,
994             (sd, place_span.0),
995             &borrow_set,
996             flow_state.borrows_in_scope(location),
997             |this, borrow_index, borrow| match (rw, borrow.kind) {
998                 // Obviously an activation is compatible with its own
999                 // reservation (or even prior activating uses of same
1000                 // borrow); so don't check if they interfere.
1001                 //
1002                 // NOTE: *reservations* do conflict with themselves;
1003                 // thus aren't injecting unsoundenss w/ this check.)
1004                 (Activation(_, activating), _) if activating == borrow_index => {
1005                     debug!(
1006                         "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1007                          skipping {:?} b/c activation of same borrow_index",
1008                         place_span,
1009                         sd,
1010                         rw,
1011                         (borrow_index, borrow),
1012                     );
1013                     Control::Continue
1014                 }
1015
1016                 (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared)
1017                 | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => {
1018                     Control::Continue
1019                 }
1020
1021                 (Write(WriteKind::Move), BorrowKind::Shallow) => {
1022                     // Handled by initialization checks.
1023                     Control::Continue
1024                 }
1025
1026                 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
1027                     // Reading from mere reservations of mutable-borrows is OK.
1028                     if !is_active(&this.dominators, borrow, context.loc) {
1029                         assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind));
1030                         return Control::Continue;
1031                     }
1032
1033                     error_reported = true;
1034                     match kind {
1035                         ReadKind::Copy  => {
1036                             this.report_use_while_mutably_borrowed(context, place_span, borrow)
1037                         }
1038                         ReadKind::Borrow(bk) => {
1039                             this.report_conflicting_borrow(context, place_span, bk, &borrow)
1040                         }
1041                     }
1042                     Control::Break
1043                 }
1044
1045                 (Reservation(kind), BorrowKind::Unique)
1046                 | (Reservation(kind), BorrowKind::Mut { .. })
1047                 | (Activation(kind, _), _)
1048                 | (Write(kind), _) => {
1049                     match rw {
1050                         Reservation(_) => {
1051                             debug!(
1052                                 "recording invalid reservation of \
1053                                  place: {:?}",
1054                                 place_span.0
1055                             );
1056                             this.reservation_error_reported.insert(place_span.0.clone());
1057                         }
1058                         Activation(_, activating) => {
1059                             debug!(
1060                                 "observing check_place for activation of \
1061                                  borrow_index: {:?}",
1062                                 activating
1063                             );
1064                         }
1065                         Read(..) | Write(..) => {}
1066                     }
1067
1068                     error_reported = true;
1069                     match kind {
1070                         WriteKind::MutableBorrow(bk) => {
1071                             this.report_conflicting_borrow(context, place_span, bk, &borrow)
1072                         }
1073                         WriteKind::StorageDeadOrDrop => {
1074                             this.report_borrowed_value_does_not_live_long_enough(
1075                                 context,
1076                                 borrow,
1077                                 place_span,
1078                                 Some(kind))
1079                         }
1080                         WriteKind::Mutate => {
1081                             this.report_illegal_mutation_of_borrowed(context, place_span, borrow)
1082                         }
1083                         WriteKind::Move => {
1084                             this.report_move_out_while_borrowed(context, place_span, &borrow)
1085                         }
1086                     }
1087                     Control::Break
1088                 }
1089             },
1090         );
1091
1092         error_reported
1093     }
1094
1095     fn mutate_place(
1096         &mut self,
1097         context: Context,
1098         place_span: (&Place<'tcx>, Span),
1099         kind: AccessDepth,
1100         mode: MutateMode,
1101         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1102     ) {
1103         // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
1104         match mode {
1105             MutateMode::WriteAndRead => {
1106                 self.check_if_path_or_subpath_is_moved(
1107                     context,
1108                     InitializationRequiringAction::Update,
1109                     place_span,
1110                     flow_state,
1111                 );
1112             }
1113             MutateMode::JustWrite => {
1114                 self.check_if_assigned_path_is_moved(context, place_span, flow_state);
1115             }
1116         }
1117
1118         // Special case: you can assign a immutable local variable
1119         // (e.g., `x = ...`) so long as it has never been initialized
1120         // before (at this point in the flow).
1121         if let &Place::Local(local) = place_span.0 {
1122             if let Mutability::Not = self.mir.local_decls[local].mutability {
1123                 // check for reassignments to immutable local variables
1124                 self.check_if_reassignment_to_immutable_state(
1125                     context,
1126                     local,
1127                     place_span,
1128                     flow_state,
1129                 );
1130                 return;
1131             }
1132         }
1133
1134         // Otherwise, use the normal access permission rules.
1135         self.access_place(
1136             context,
1137             place_span,
1138             (kind, Write(WriteKind::Mutate)),
1139             LocalMutationIsAllowed::No,
1140             flow_state,
1141         );
1142     }
1143
1144     fn consume_rvalue(
1145         &mut self,
1146         context: Context,
1147         (rvalue, span): (&Rvalue<'tcx>, Span),
1148         _location: Location,
1149         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1150     ) {
1151         match *rvalue {
1152             Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
1153                 let access_kind = match bk {
1154                     BorrowKind::Shallow => {
1155                         (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
1156                     },
1157                     BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
1158                     BorrowKind::Unique | BorrowKind::Mut { .. } => {
1159                         let wk = WriteKind::MutableBorrow(bk);
1160                         if allow_two_phase_borrow(&self.infcx.tcx, bk) {
1161                             (Deep, Reservation(wk))
1162                         } else {
1163                             (Deep, Write(wk))
1164                         }
1165                     }
1166                 };
1167
1168                 self.access_place(
1169                     context,
1170                     (place, span),
1171                     access_kind,
1172                     LocalMutationIsAllowed::No,
1173                     flow_state,
1174                 );
1175
1176                 let action = if bk == BorrowKind::Shallow {
1177                     InitializationRequiringAction::MatchOn
1178                 } else {
1179                     InitializationRequiringAction::Borrow
1180                 };
1181
1182                 self.check_if_path_or_subpath_is_moved(
1183                     context,
1184                     action,
1185                     (place, span),
1186                     flow_state,
1187                 );
1188             }
1189
1190             Rvalue::Use(ref operand)
1191             | Rvalue::Repeat(ref operand, _)
1192             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
1193             | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
1194                 self.consume_operand(context, (operand, span), flow_state)
1195             }
1196
1197             Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
1198                 let af = match *rvalue {
1199                     Rvalue::Len(..) => ArtificialField::ArrayLength,
1200                     Rvalue::Discriminant(..) => ArtificialField::Discriminant,
1201                     _ => unreachable!(),
1202                 };
1203                 self.access_place(
1204                     context,
1205                     (place, span),
1206                     (Shallow(Some(af)), Read(ReadKind::Copy)),
1207                     LocalMutationIsAllowed::No,
1208                     flow_state,
1209                 );
1210                 self.check_if_path_or_subpath_is_moved(
1211                     context,
1212                     InitializationRequiringAction::Use,
1213                     (place, span),
1214                     flow_state,
1215                 );
1216             }
1217
1218             Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
1219             | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
1220                 self.consume_operand(context, (operand1, span), flow_state);
1221                 self.consume_operand(context, (operand2, span), flow_state);
1222             }
1223
1224             Rvalue::NullaryOp(_op, _ty) => {
1225                 // nullary ops take no dynamic input; no borrowck effect.
1226                 //
1227                 // FIXME: is above actually true? Do we want to track
1228                 // the fact that uninitialized data can be created via
1229                 // `NullOp::Box`?
1230             }
1231
1232             Rvalue::Aggregate(ref aggregate_kind, ref operands) => {
1233                 // We need to report back the list of mutable upvars that were
1234                 // moved into the closure and subsequently used by the closure,
1235                 // in order to populate our used_mut set.
1236                 match **aggregate_kind {
1237                     AggregateKind::Closure(def_id, _)
1238                     | AggregateKind::Generator(def_id, _, _) => {
1239                         let BorrowCheckResult {
1240                             used_mut_upvars, ..
1241                         } = self.infcx.tcx.mir_borrowck(def_id);
1242                         debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1243                         for field in used_mut_upvars {
1244                             // This relies on the current way that by-value
1245                             // captures of a closure are copied/moved directly
1246                             // when generating MIR.
1247                             match operands[field.index()] {
1248                                 Operand::Move(Place::Local(local))
1249                                 | Operand::Copy(Place::Local(local)) => {
1250                                     self.used_mut.insert(local);
1251                                 }
1252                                 Operand::Move(ref place @ Place::Projection(_))
1253                                 | Operand::Copy(ref place @ Place::Projection(_)) => {
1254                                     if let Some(field) = place.is_upvar_field_projection(
1255                                             self.mir, &self.infcx.tcx) {
1256                                         self.used_mut_upvars.push(field);
1257                                     }
1258                                 }
1259                                 Operand::Move(Place::Static(..))
1260                                 | Operand::Copy(Place::Static(..))
1261                                 | Operand::Move(Place::Promoted(..))
1262                                 | Operand::Copy(Place::Promoted(..))
1263                                 | Operand::Constant(..) => {}
1264                             }
1265                         }
1266                     }
1267                     AggregateKind::Adt(..)
1268                     | AggregateKind::Array(..)
1269                     | AggregateKind::Tuple { .. } => (),
1270                 }
1271
1272                 for operand in operands {
1273                     self.consume_operand(context, (operand, span), flow_state);
1274                 }
1275             }
1276         }
1277     }
1278
1279     fn consume_operand(
1280         &mut self,
1281         context: Context,
1282         (operand, span): (&Operand<'tcx>, Span),
1283         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1284     ) {
1285         match *operand {
1286             Operand::Copy(ref place) => {
1287                 // copy of place: check if this is "copy of frozen path"
1288                 // (FIXME: see check_loans.rs)
1289                 self.access_place(
1290                     context,
1291                     (place, span),
1292                     (Deep, Read(ReadKind::Copy)),
1293                     LocalMutationIsAllowed::No,
1294                     flow_state,
1295                 );
1296
1297                 // Finally, check if path was already moved.
1298                 self.check_if_path_or_subpath_is_moved(
1299                     context,
1300                     InitializationRequiringAction::Use,
1301                     (place, span),
1302                     flow_state,
1303                 );
1304             }
1305             Operand::Move(ref place) => {
1306                 // move of place: check if this is move of already borrowed path
1307                 self.access_place(
1308                     context,
1309                     (place, span),
1310                     (Deep, Write(WriteKind::Move)),
1311                     LocalMutationIsAllowed::Yes,
1312                     flow_state,
1313                 );
1314
1315                 // Finally, check if path was already moved.
1316                 self.check_if_path_or_subpath_is_moved(
1317                     context,
1318                     InitializationRequiringAction::Use,
1319                     (place, span),
1320                     flow_state,
1321                 );
1322             }
1323             Operand::Constant(_) => {}
1324         }
1325     }
1326
1327     /// Checks whether a borrow of this place is invalidated when the function
1328     /// exits
1329     fn check_for_invalidation_at_exit(
1330         &mut self,
1331         context: Context,
1332         borrow: &BorrowData<'tcx>,
1333         span: Span,
1334     ) {
1335         debug!("check_for_invalidation_at_exit({:?})", borrow);
1336         let place = &borrow.borrowed_place;
1337         let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
1338
1339         // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
1340         // we just know that all locals are dropped at function exit (otherwise
1341         // we'll have a memory leak) and assume that all statics have a destructor.
1342         //
1343         // FIXME: allow thread-locals to borrow other thread locals?
1344         let (might_be_alive, will_be_dropped) = match root_place {
1345             Place::Promoted(_) => (true, false),
1346             Place::Static(_) => {
1347                 // Thread-locals might be dropped after the function exits, but
1348                 // "true" statics will never be.
1349                 let is_thread_local = self.is_place_thread_local(&root_place);
1350                 (true, is_thread_local)
1351             }
1352             Place::Local(_) => {
1353                 // Locals are always dropped at function exit, and if they
1354                 // have a destructor it would've been called already.
1355                 (false, self.locals_are_invalidated_at_exit)
1356             }
1357             Place::Projection(..) => {
1358                 bug!("root of {:?} is a projection ({:?})?", place, root_place)
1359             }
1360         };
1361
1362         if !will_be_dropped {
1363             debug!(
1364                 "place_is_invalidated_at_exit({:?}) - won't be dropped",
1365                 place
1366             );
1367             return;
1368         }
1369
1370         let sd = if might_be_alive { Deep } else { Shallow(None) };
1371
1372         if places_conflict::borrow_conflicts_with_place(
1373             self.infcx.tcx,
1374             self.mir,
1375             place,
1376             borrow.kind,
1377             root_place,
1378             sd
1379         ) {
1380             debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1381             // FIXME: should be talking about the region lifetime instead
1382             // of just a span here.
1383             let span = self.infcx.tcx.sess.source_map().end_point(span);
1384             self.report_borrowed_value_does_not_live_long_enough(
1385                 context,
1386                 borrow,
1387                 (place, span),
1388                 None,
1389             )
1390         }
1391     }
1392
1393     /// Reports an error if this is a borrow of local data.
1394     /// This is called for all Yield statements on movable generators
1395     fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1396         debug!("check_for_local_borrow({:?})", borrow);
1397
1398         if borrow_of_local_data(&borrow.borrowed_place) {
1399             let err = self.infcx.tcx
1400                 .cannot_borrow_across_generator_yield(
1401                     self.retrieve_borrow_spans(borrow).var_or_use(),
1402                     yield_span,
1403                     Origin::Mir,
1404                 );
1405
1406             err.buffer(&mut self.errors_buffer);
1407         }
1408     }
1409
1410     fn check_activations(
1411         &mut self,
1412         location: Location,
1413         span: Span,
1414         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1415     ) {
1416         if !self.infcx.tcx.two_phase_borrows() {
1417             return;
1418         }
1419
1420         // Two-phase borrow support: For each activation that is newly
1421         // generated at this statement, check if it interferes with
1422         // another borrow.
1423         let borrow_set = self.borrow_set.clone();
1424         for &borrow_index in borrow_set.activations_at_location(location) {
1425             let borrow = &borrow_set[borrow_index];
1426
1427             // only mutable borrows should be 2-phase
1428             assert!(match borrow.kind {
1429                 BorrowKind::Shared | BorrowKind::Shallow => false,
1430                 BorrowKind::Unique | BorrowKind::Mut { .. } => true,
1431             });
1432
1433             self.access_place(
1434                 ContextKind::Activation.new(location),
1435                 (&borrow.borrowed_place, span),
1436                 (
1437                     Deep,
1438                     Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index),
1439                 ),
1440                 LocalMutationIsAllowed::No,
1441                 flow_state,
1442             );
1443             // We do not need to call `check_if_path_or_subpath_is_moved`
1444             // again, as we already called it when we made the
1445             // initial reservation.
1446         }
1447     }
1448 }
1449
1450 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1451     fn check_if_reassignment_to_immutable_state(
1452         &mut self,
1453         context: Context,
1454         local: Local,
1455         place_span: (&Place<'tcx>, Span),
1456         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1457     ) {
1458         debug!("check_if_reassignment_to_immutable_state({:?})", local);
1459
1460         // Check if any of the initializiations of `local` have happened yet:
1461         if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
1462             // And, if so, report an error.
1463             let init = &self.move_data.inits[init_index];
1464             let span = init.span(&self.mir);
1465             self.report_illegal_reassignment(
1466                 context, place_span, span, place_span.0
1467             );
1468         }
1469     }
1470
1471     fn check_if_full_path_is_moved(
1472         &mut self,
1473         context: Context,
1474         desired_action: InitializationRequiringAction,
1475         place_span: (&Place<'tcx>, Span),
1476         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1477     ) {
1478         let maybe_uninits = &flow_state.uninits;
1479
1480         // Bad scenarios:
1481         //
1482         // 1. Move of `a.b.c`, use of `a.b.c`
1483         // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`)
1484         // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
1485         //    partial initialization support, one might have `a.x`
1486         //    initialized but not `a.b`.
1487         //
1488         // OK scenarios:
1489         //
1490         // 4. Move of `a.b.c`, use of `a.b.d`
1491         // 5. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1492         // 6. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1493         //    must have been initialized for the use to be sound.
1494         // 7. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1495
1496         // The dataflow tracks shallow prefixes distinctly (that is,
1497         // field-accesses on P distinctly from P itself), in order to
1498         // track substructure initialization separately from the whole
1499         // structure.
1500         //
1501         // E.g., when looking at (*a.b.c).d, if the closest prefix for
1502         // which we have a MovePath is `a.b`, then that means that the
1503         // initialization state of `a.b` is all we need to inspect to
1504         // know if `a.b.c` is valid (and from that we infer that the
1505         // dereference and `.d` access is also valid, since we assume
1506         // `a.b.c` is assigned a reference to a initialized and
1507         // well-formed record structure.)
1508
1509         // Therefore, if we seek out the *closest* prefix for which we
1510         // have a MovePath, that should capture the initialization
1511         // state for the place scenario.
1512         //
1513         // This code covers scenarios 1, 2, and 3.
1514
1515         debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1516         match self.move_path_closest_to(place_span.0) {
1517             Ok((prefix, mpi)) => {
1518                 if maybe_uninits.contains(mpi) {
1519                     self.report_use_of_moved_or_uninitialized(
1520                         context,
1521                         desired_action,
1522                         (prefix, place_span.0, place_span.1),
1523                         mpi,
1524                     );
1525                     return; // don't bother finding other problems.
1526                 }
1527             }
1528             Err(NoMovePathFound::ReachedStatic) => {
1529                 // Okay: we do not build MoveData for static variables
1530             } // Only query longest prefix with a MovePath, not further
1531               // ancestors; dataflow recurs on children when parents
1532               // move (to support partial (re)inits).
1533               //
1534               // (I.e. querying parents breaks scenario 7; but may want
1535               // to do such a query based on partial-init feature-gate.)
1536         }
1537     }
1538
1539     fn check_if_path_or_subpath_is_moved(
1540         &mut self,
1541         context: Context,
1542         desired_action: InitializationRequiringAction,
1543         place_span: (&Place<'tcx>, Span),
1544         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1545     ) {
1546         let maybe_uninits = &flow_state.uninits;
1547
1548         // Bad scenarios:
1549         //
1550         // 1. Move of `a.b.c`, use of `a` or `a.b`
1551         //    partial initialization support, one might have `a.x`
1552         //    initialized but not `a.b`.
1553         // 2. All bad scenarios from `check_if_full_path_is_moved`
1554         //
1555         // OK scenarios:
1556         //
1557         // 3. Move of `a.b.c`, use of `a.b.d`
1558         // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1559         // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1560         //    must have been initialized for the use to be sound.
1561         // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1562
1563         self.check_if_full_path_is_moved(context, desired_action, place_span, flow_state);
1564
1565         // A move of any shallow suffix of `place` also interferes
1566         // with an attempt to use `place`. This is scenario 3 above.
1567         //
1568         // (Distinct from handling of scenarios 1+2+4 above because
1569         // `place` does not interfere with suffixes of its prefixes,
1570         // e.g. `a.b.c` does not interfere with `a.b.d`)
1571         //
1572         // This code covers scenario 1.
1573
1574         debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
1575         if let Some(mpi) = self.move_path_for_place(place_span.0) {
1576             if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) {
1577                 self.report_use_of_moved_or_uninitialized(
1578                     context,
1579                     desired_action,
1580                     (place_span.0, place_span.0, place_span.1),
1581                     child_mpi,
1582                 );
1583                 return; // don't bother finding other problems.
1584             }
1585         }
1586     }
1587
1588     /// Currently MoveData does not store entries for all places in
1589     /// the input MIR. For example it will currently filter out
1590     /// places that are Copy; thus we do not track places of shared
1591     /// reference type. This routine will walk up a place along its
1592     /// prefixes, searching for a foundational place that *is*
1593     /// tracked in the MoveData.
1594     ///
1595     /// An Err result includes a tag indicated why the search failed.
1596     /// Currently this can only occur if the place is built off of a
1597     /// static variable, as we do not track those in the MoveData.
1598     fn move_path_closest_to<'a>(
1599         &mut self,
1600         place: &'a Place<'tcx>,
1601     ) -> Result<(&'a Place<'tcx>, MovePathIndex), NoMovePathFound> where 'cx: 'a {
1602         let mut last_prefix = place;
1603         for prefix in self.prefixes(place, PrefixSet::All) {
1604             if let Some(mpi) = self.move_path_for_place(prefix) {
1605                 return Ok((prefix, mpi));
1606             }
1607             last_prefix = prefix;
1608         }
1609         match *last_prefix {
1610             Place::Local(_) => panic!("should have move path for every Local"),
1611             Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
1612             Place::Promoted(_) |
1613             Place::Static(_) => Err(NoMovePathFound::ReachedStatic),
1614         }
1615     }
1616
1617     fn move_path_for_place(&mut self, place: &Place<'tcx>) -> Option<MovePathIndex> {
1618         // If returns None, then there is no move path corresponding
1619         // to a direct owner of `place` (which means there is nothing
1620         // that borrowck tracks for its analysis).
1621
1622         match self.move_data.rev_lookup.find(place) {
1623             LookupResult::Parent(_) => None,
1624             LookupResult::Exact(mpi) => Some(mpi),
1625         }
1626     }
1627
1628     fn check_if_assigned_path_is_moved(
1629         &mut self,
1630         context: Context,
1631         (place, span): (&Place<'tcx>, Span),
1632         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1633     ) {
1634         debug!("check_if_assigned_path_is_moved place: {:?}", place);
1635         // recur down place; dispatch to external checks when necessary
1636         let mut place = place;
1637         loop {
1638             match *place {
1639                 Place::Promoted(_) |
1640                 Place::Local(_) | Place::Static(_) => {
1641                     // assigning to `x` does not require `x` be initialized.
1642                     break;
1643                 }
1644                 Place::Projection(ref proj) => {
1645                     let Projection { ref base, ref elem } = **proj;
1646                     match *elem {
1647                         ProjectionElem::Index(_/*operand*/) |
1648                         ProjectionElem::ConstantIndex { .. } |
1649                         // assigning to P[i] requires P to be valid.
1650                         ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
1651                         // assigning to (P->variant) is okay if assigning to `P` is okay
1652                         //
1653                         // FIXME: is this true even if P is a adt with a dtor?
1654                         { }
1655
1656                         // assigning to (*P) requires P to be initialized
1657                         ProjectionElem::Deref => {
1658                             self.check_if_full_path_is_moved(
1659                                 context, InitializationRequiringAction::Use,
1660                                 (base, span), flow_state);
1661                             // (base initialized; no need to
1662                             // recur further)
1663                             break;
1664                         }
1665
1666                         ProjectionElem::Subslice { .. } => {
1667                             panic!("we don't allow assignments to subslices, context: {:?}",
1668                                    context);
1669                         }
1670
1671                         ProjectionElem::Field(..) => {
1672                             // if type of `P` has a dtor, then
1673                             // assigning to `P.f` requires `P` itself
1674                             // be already initialized
1675                             let tcx = self.infcx.tcx;
1676                             match base.ty(self.mir, tcx).to_ty(tcx).sty {
1677                                 ty::Adt(def, _) if def.has_dtor(tcx) => {
1678                                     self.check_if_path_or_subpath_is_moved(
1679                                         context, InitializationRequiringAction::Assignment,
1680                                         (base, span), flow_state);
1681
1682                                     // (base initialized; no need to
1683                                     // recur further)
1684                                     break;
1685                                 }
1686
1687
1688                                 // Once `let s; s.x = V; read(s.x);`,
1689                                 // is allowed, remove this match arm.
1690                                 ty::Adt(..) | ty::Tuple(..) => {
1691                                     check_parent_of_field(self, context, base, span, flow_state);
1692
1693                                     if let Some(local) = place.base_local() {
1694                                         // rust-lang/rust#21232,
1695                                         // #54499, #54986: during
1696                                         // period where we reject
1697                                         // partial initialization, do
1698                                         // not complain about
1699                                         // unnecessary `mut` on an
1700                                         // attempt to do a partial
1701                                         // initialization.
1702                                         self.used_mut.insert(local);
1703                                     }
1704                                 }
1705
1706                                 _ => {}
1707                             }
1708                         }
1709                     }
1710
1711                     place = base;
1712                     continue;
1713                 }
1714             }
1715         }
1716
1717         fn check_parent_of_field<'cx, 'gcx, 'tcx>(
1718             this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
1719             context: Context,
1720             base: &Place<'tcx>,
1721             span: Span,
1722             flow_state: &Flows<'cx, 'gcx, 'tcx>,
1723         ) {
1724             // rust-lang/rust#21232: Until Rust allows reads from the
1725             // initialized parts of partially initialized structs, we
1726             // will, starting with the 2018 edition, reject attempts
1727             // to write to structs that are not fully initialized.
1728             //
1729             // In other words, *until* we allow this:
1730             //
1731             // 1. `let mut s; s.x = Val; read(s.x);`
1732             //
1733             // we will for now disallow this:
1734             //
1735             // 2. `let mut s; s.x = Val;`
1736             //
1737             // and also this:
1738             //
1739             // 3. `let mut s = ...; drop(s); s.x=Val;`
1740             //
1741             // This does not use check_if_path_or_subpath_is_moved,
1742             // because we want to *allow* reinitializations of fields:
1743             // e.g. want to allow
1744             //
1745             // `let mut s = ...; drop(s.x); s.x=Val;`
1746             //
1747             // This does not use check_if_full_path_is_moved on
1748             // `base`, because that would report an error about the
1749             // `base` as a whole, but in this scenario we *really*
1750             // want to report an error about the actual thing that was
1751             // moved, which may be some prefix of `base`.
1752
1753             // Shallow so that we'll stop at any dereference; we'll
1754             // report errors about issues with such bases elsewhere.
1755             let maybe_uninits = &flow_state.uninits;
1756
1757             // Find the shortest uninitialized prefix you can reach
1758             // without going over a Deref.
1759             let mut shortest_uninit_seen = None;
1760             for prefix in this.prefixes(base, PrefixSet::Shallow) {
1761                 let mpi = match this.move_path_for_place(prefix) {
1762                     Some(mpi) => mpi, None => continue,
1763                 };
1764
1765                 if maybe_uninits.contains(mpi) {
1766                     debug!("check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
1767                            shortest_uninit_seen, Some((prefix, mpi)));
1768                     shortest_uninit_seen = Some((prefix, mpi));
1769                 } else {
1770                     debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
1771                 }
1772             }
1773
1774             if let Some((prefix, mpi)) = shortest_uninit_seen {
1775                 // Check for a reassignment into a uninitialized field of a union (for example,
1776                 // after a move out). In this case, do not report a error here. There is an
1777                 // exception, if this is the first assignment into the union (that is, there is
1778                 // no move out from an earlier location) then this is an attempt at initialization
1779                 // of the union - we should error in that case.
1780                 let tcx = this.infcx.tcx;
1781                 if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty {
1782                     if def.is_union() {
1783                         if this.move_data.path_map[mpi].iter().any(|moi| {
1784                             this.move_data.moves[*moi].source.is_predecessor_of(
1785                                 context.loc, this.mir,
1786                             )
1787                         }) {
1788                             return;
1789                         }
1790                     }
1791                 }
1792
1793                 this.report_use_of_moved_or_uninitialized(
1794                     context,
1795                     InitializationRequiringAction::PartialAssignment,
1796                     (prefix, base, span),
1797                     mpi,
1798                 );
1799             }
1800         }
1801     }
1802
1803     /// Check the permissions for the given place and read or write kind
1804     ///
1805     /// Returns true if an error is reported, false otherwise.
1806     fn check_access_permissions(
1807         &mut self,
1808         (place, span): (&Place<'tcx>, Span),
1809         kind: ReadOrWrite,
1810         is_local_mutation_allowed: LocalMutationIsAllowed,
1811         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1812         location: Location,
1813     ) -> bool {
1814         debug!(
1815             "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
1816             place, kind, is_local_mutation_allowed
1817         );
1818
1819         let error_access;
1820         let the_place_err;
1821
1822         // rust-lang/rust#21232, #54986: during period where we reject
1823         // partial initialization, do not complain about mutability
1824         // errors except for actual mutation (as opposed to an attempt
1825         // to do a partial initialization).
1826         let previously_initialized = if let Some(local) = place.base_local() {
1827             self.is_local_ever_initialized(local, flow_state).is_some()
1828         } else {
1829             true
1830         };
1831
1832         match kind {
1833             Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
1834             | Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. }))
1835             | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
1836             | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => {
1837                 let is_local_mutation_allowed = match borrow_kind {
1838                     BorrowKind::Unique => LocalMutationIsAllowed::Yes,
1839                     BorrowKind::Mut { .. } => is_local_mutation_allowed,
1840                     BorrowKind::Shared | BorrowKind::Shallow => unreachable!(),
1841                 };
1842                 match self.is_mutable(place, is_local_mutation_allowed) {
1843                     Ok(root_place) => {
1844                         self.add_used_mut(root_place, flow_state);
1845                         return false;
1846                     }
1847                     Err(place_err) => {
1848                         error_access = AccessKind::MutableBorrow;
1849                         the_place_err = place_err;
1850                     }
1851                 }
1852             }
1853             Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
1854                 match self.is_mutable(place, is_local_mutation_allowed) {
1855                     Ok(root_place) => {
1856                         self.add_used_mut(root_place, flow_state);
1857                         return false;
1858                     }
1859                     Err(place_err) => {
1860                         error_access = AccessKind::Mutate;
1861                         the_place_err = place_err;
1862                     }
1863                 }
1864             }
1865
1866             Reservation(wk @ WriteKind::Move)
1867             | Write(wk @ WriteKind::Move)
1868             | Reservation(wk @ WriteKind::StorageDeadOrDrop)
1869             | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
1870             | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow))
1871             | Write(wk @ WriteKind::StorageDeadOrDrop)
1872             | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
1873             | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => {
1874                 if let (Err(_place_err), true) = (
1875                     self.is_mutable(place, is_local_mutation_allowed),
1876                     self.errors_buffer.is_empty()
1877                 ) {
1878                     if self.infcx.tcx.migrate_borrowck() {
1879                         // rust-lang/rust#46908: In pure NLL mode this
1880                         // code path should be unreachable (and thus
1881                         // we signal an ICE in the else branch
1882                         // here). But we can legitimately get here
1883                         // under borrowck=migrate mode, so instead of
1884                         // ICE'ing we instead report a legitimate
1885                         // error (which will then be downgraded to a
1886                         // warning by the migrate machinery).
1887                         error_access = match wk {
1888                             WriteKind::MutableBorrow(_) => AccessKind::MutableBorrow,
1889                             WriteKind::Move => AccessKind::Move,
1890                             WriteKind::StorageDeadOrDrop |
1891                             WriteKind::Mutate => AccessKind::Mutate,
1892                         };
1893                         self.report_mutability_error(
1894                             place,
1895                             span,
1896                             _place_err,
1897                             error_access,
1898                             location,
1899                         );
1900                     } else {
1901                         span_bug!(
1902                             span,
1903                             "Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
1904                             place,
1905                             kind,
1906                         );
1907                     }
1908                 }
1909                 return false;
1910             }
1911             Activation(..) => {
1912                 // permission checks are done at Reservation point.
1913                 return false;
1914             }
1915             Read(ReadKind::Borrow(BorrowKind::Unique))
1916             | Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
1917             | Read(ReadKind::Borrow(BorrowKind::Shared))
1918             | Read(ReadKind::Borrow(BorrowKind::Shallow))
1919             | Read(ReadKind::Copy) => {
1920                 // Access authorized
1921                 return false;
1922             }
1923         }
1924
1925         // at this point, we have set up the error reporting state.
1926         return if previously_initialized {
1927             self.report_mutability_error(
1928                 place,
1929                 span,
1930                 the_place_err,
1931                 error_access,
1932                 location,
1933             );
1934             true
1935         } else {
1936             false
1937         };
1938     }
1939
1940     fn is_local_ever_initialized(&self,
1941                                  local: Local,
1942                                  flow_state: &Flows<'cx, 'gcx, 'tcx>)
1943                                  -> Option<InitIndex>
1944     {
1945         let mpi = self.move_data.rev_lookup.find_local(local);
1946         let ii = &self.move_data.init_path_map[mpi];
1947         for &index in ii {
1948             if flow_state.ever_inits.contains(index) {
1949                 return Some(index);
1950             }
1951         }
1952         None
1953     }
1954
1955     /// Adds the place into the used mutable variables set
1956     fn add_used_mut<'d>(
1957         &mut self,
1958         root_place: RootPlace<'d, 'tcx>,
1959         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1960     ) {
1961         match root_place {
1962             RootPlace {
1963                 place: Place::Local(local),
1964                 is_local_mutation_allowed,
1965             } => {
1966                 // If the local may have been initialized, and it is now currently being
1967                 // mutated, then it is justified to be annotated with the `mut`
1968                 // keyword, since the mutation may be a possible reassignment.
1969                 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes &&
1970                     self.is_local_ever_initialized(*local, flow_state).is_some()
1971                 {
1972                     self.used_mut.insert(*local);
1973                 }
1974             }
1975             RootPlace {
1976                 place: _,
1977                 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
1978             } => {}
1979             RootPlace {
1980                 place: place @ Place::Projection(_),
1981                 is_local_mutation_allowed: _,
1982             } => {
1983                 if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) {
1984                     self.used_mut_upvars.push(field);
1985                 }
1986             }
1987             RootPlace {
1988                 place: Place::Promoted(..),
1989                 is_local_mutation_allowed: _,
1990             } => {}
1991             RootPlace {
1992                 place: Place::Static(..),
1993                 is_local_mutation_allowed: _,
1994             } => {}
1995         }
1996     }
1997
1998     /// Whether this value can be written or borrowed mutably.
1999     /// Returns the root place if the place passed in is a projection.
2000     fn is_mutable<'d>(
2001         &self,
2002         place: &'d Place<'tcx>,
2003         is_local_mutation_allowed: LocalMutationIsAllowed,
2004     ) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> {
2005         match *place {
2006             Place::Local(local) => {
2007                 let local = &self.mir.local_decls[local];
2008                 match local.mutability {
2009                     Mutability::Not => match is_local_mutation_allowed {
2010                         LocalMutationIsAllowed::Yes => Ok(RootPlace {
2011                             place,
2012                             is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2013                         }),
2014                         LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2015                             place,
2016                             is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2017                         }),
2018                         LocalMutationIsAllowed::No => Err(place),
2019                     },
2020                     Mutability::Mut => Ok(RootPlace {
2021                         place,
2022                         is_local_mutation_allowed,
2023                     }),
2024                 }
2025             }
2026             // The rules for promotion are made by `qualify_consts`, there wouldn't even be a
2027             // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
2028             Place::Promoted(_) => Ok(RootPlace {
2029                 place,
2030                 is_local_mutation_allowed,
2031             }),
2032             Place::Static(ref static_) => {
2033                 if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
2034                     Err(place)
2035                 } else {
2036                     Ok(RootPlace {
2037                         place,
2038                         is_local_mutation_allowed,
2039                     })
2040                 }
2041             }
2042             Place::Projection(ref proj) => {
2043                 match proj.elem {
2044                     ProjectionElem::Deref => {
2045                         let base_ty = proj.base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
2046
2047                         // Check the kind of deref to decide
2048                         match base_ty.sty {
2049                             ty::Ref(_, _, mutbl) => {
2050                                 match mutbl {
2051                                     // Shared borrowed data is never mutable
2052                                     hir::MutImmutable => Err(place),
2053                                     // Mutably borrowed data is mutable, but only if we have a
2054                                     // unique path to the `&mut`
2055                                     hir::MutMutable => {
2056                                         let mode = match place.is_upvar_field_projection(
2057                                             self.mir, &self.infcx.tcx)
2058                                         {
2059                                             Some(field)
2060                                                 if {
2061                                                     self.mir.upvar_decls[field.index()].by_ref
2062                                                 } =>
2063                                             {
2064                                                 is_local_mutation_allowed
2065                                             }
2066                                             _ => LocalMutationIsAllowed::Yes,
2067                                         };
2068
2069                                         self.is_mutable(&proj.base, mode)
2070                                     }
2071                                 }
2072                             }
2073                             ty::RawPtr(tnm) => {
2074                                 match tnm.mutbl {
2075                                     // `*const` raw pointers are not mutable
2076                                     hir::MutImmutable => Err(place),
2077                                     // `*mut` raw pointers are always mutable, regardless of
2078                                     // context. The users have to check by themselves.
2079                                     hir::MutMutable => {
2080                                         Ok(RootPlace {
2081                                             place,
2082                                             is_local_mutation_allowed,
2083                                         })
2084                                     }
2085                                 }
2086                             }
2087                             // `Box<T>` owns its content, so mutable if its location is mutable
2088                             _ if base_ty.is_box() => {
2089                                 self.is_mutable(&proj.base, is_local_mutation_allowed)
2090                             }
2091                             // Deref should only be for reference, pointers or boxes
2092                             _ => bug!("Deref of unexpected type: {:?}", base_ty),
2093                         }
2094                     }
2095                     // All other projections are owned by their base path, so mutable if
2096                     // base path is mutable
2097                     ProjectionElem::Field(..)
2098                     | ProjectionElem::Index(..)
2099                     | ProjectionElem::ConstantIndex { .. }
2100                     | ProjectionElem::Subslice { .. }
2101                     | ProjectionElem::Downcast(..) => {
2102                         let upvar_field_projection = place.is_upvar_field_projection(
2103                             self.mir, &self.infcx.tcx);
2104                         if let Some(field) = upvar_field_projection {
2105                             let decl = &self.mir.upvar_decls[field.index()];
2106                             debug!(
2107                                 "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
2108                                 decl, is_local_mutation_allowed, place
2109                             );
2110                             match (decl.mutability, is_local_mutation_allowed) {
2111                                 (Mutability::Not, LocalMutationIsAllowed::No)
2112                                 | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => {
2113                                     Err(place)
2114                                 }
2115                                 (Mutability::Not, LocalMutationIsAllowed::Yes)
2116                                 | (Mutability::Mut, _) => {
2117                                     // Subtle: this is an upvar
2118                                     // reference, so it looks like
2119                                     // `self.foo` -- we want to double
2120                                     // check that the context `*self`
2121                                     // is mutable (i.e., this is not a
2122                                     // `Fn` closure).  But if that
2123                                     // check succeeds, we want to
2124                                     // *blame* the mutability on
2125                                     // `place` (that is,
2126                                     // `self.foo`). This is used to
2127                                     // propagate the info about
2128                                     // whether mutability declarations
2129                                     // are used outwards, so that we register
2130                                     // the outer variable as mutable. Otherwise a
2131                                     // test like this fails to record the `mut`
2132                                     // as needed:
2133                                     //
2134                                     // ```
2135                                     // fn foo<F: FnOnce()>(_f: F) { }
2136                                     // fn main() {
2137                                     //     let var = Vec::new();
2138                                     //     foo(move || {
2139                                     //         var.push(1);
2140                                     //     });
2141                                     // }
2142                                     // ```
2143                                     let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?;
2144                                     Ok(RootPlace {
2145                                         place,
2146                                         is_local_mutation_allowed,
2147                                     })
2148                                 }
2149                             }
2150                         } else {
2151                             self.is_mutable(&proj.base, is_local_mutation_allowed)
2152                         }
2153                     }
2154                 }
2155             }
2156         }
2157     }
2158 }
2159
2160 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2161 enum NoMovePathFound {
2162     ReachedStatic,
2163 }
2164
2165 /// The degree of overlap between 2 places for borrow-checking.
2166 enum Overlap {
2167     /// The places might partially overlap - in this case, we give
2168     /// up and say that they might conflict. This occurs when
2169     /// different fields of a union are borrowed. For example,
2170     /// if `u` is a union, we have no way of telling how disjoint
2171     /// `u.a.x` and `a.b.y` are.
2172     Arbitrary,
2173     /// The places have the same type, and are either completely disjoint
2174     /// or equal - i.e. they can't "partially" overlap as can occur with
2175     /// unions. This is the "base case" on which we recur for extensions
2176     /// of the place.
2177     EqualOrDisjoint,
2178     /// The places are disjoint, so we know all extensions of them
2179     /// will also be disjoint.
2180     Disjoint,
2181 }
2182
2183 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2184 struct Context {
2185     kind: ContextKind,
2186     loc: Location,
2187 }
2188
2189 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2190 enum ContextKind {
2191     Activation,
2192     AssignLhs,
2193     AssignRhs,
2194     SetDiscrim,
2195     InlineAsm,
2196     SwitchInt,
2197     Drop,
2198     DropAndReplace,
2199     CallOperator,
2200     CallOperand,
2201     CallDest,
2202     Assert,
2203     Yield,
2204     FakeRead,
2205     StorageDead,
2206 }
2207
2208 impl ContextKind {
2209     fn new(self, loc: Location) -> Context {
2210         Context {
2211             kind: self,
2212             loc,
2213         }
2214     }
2215 }