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