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