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