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