]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/mod.rs
Auto merge of #53516 - petrochenkov:derregr, r=estebank
[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.source_map().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         // Check is_empty() first because it's the common case, and doing that
1084         // way we avoid the clone() call.
1085         if !self.access_place_error_reported.is_empty() &&
1086            self
1087             .access_place_error_reported
1088             .contains(&(place_span.0.clone(), place_span.1))
1089         {
1090             debug!(
1091                 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1092                 place_span, kind
1093             );
1094             return;
1095         }
1096
1097         let mutability_error =
1098             self.check_access_permissions(
1099                 place_span,
1100                 rw,
1101                 is_local_mutation_allowed,
1102                 flow_state,
1103                 context.loc,
1104             );
1105         let conflict_error =
1106             self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
1107
1108         if conflict_error || mutability_error {
1109             debug!(
1110                 "access_place: logging error place_span=`{:?}` kind=`{:?}`",
1111                 place_span, kind
1112             );
1113             self.access_place_error_reported
1114                 .insert((place_span.0.clone(), place_span.1));
1115         }
1116     }
1117
1118     fn check_access_for_conflict(
1119         &mut self,
1120         context: Context,
1121         place_span: (&Place<'tcx>, Span),
1122         sd: ShallowOrDeep,
1123         rw: ReadOrWrite,
1124         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1125     ) -> bool {
1126         debug!(
1127             "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
1128             context, place_span, sd, rw,
1129         );
1130
1131         let mut error_reported = false;
1132         let tcx = self.tcx;
1133         let mir = self.mir;
1134         let location = self.location_table.start_index(context.loc);
1135         let borrow_set = self.borrow_set.clone();
1136         each_borrow_involving_path(
1137             self,
1138             tcx,
1139             mir,
1140             context,
1141             (sd, place_span.0),
1142             &borrow_set,
1143             flow_state.borrows_in_scope(location),
1144             |this, borrow_index, borrow| match (rw, borrow.kind) {
1145                 // Obviously an activation is compatible with its own
1146                 // reservation (or even prior activating uses of same
1147                 // borrow); so don't check if they interfere.
1148                 //
1149                 // NOTE: *reservations* do conflict with themselves;
1150                 // thus aren't injecting unsoundenss w/ this check.)
1151                 (Activation(_, activating), _) if activating == borrow_index => {
1152                     debug!(
1153                         "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1154                          skipping {:?} b/c activation of same borrow_index",
1155                         place_span,
1156                         sd,
1157                         rw,
1158                         (borrow_index, borrow),
1159                     );
1160                     Control::Continue
1161                 }
1162
1163                 (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => {
1164                     Control::Continue
1165                 }
1166
1167                 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
1168                     // Reading from mere reservations of mutable-borrows is OK.
1169                     if !is_active(&this.dominators, borrow, context.loc) {
1170                         assert!(allow_two_phase_borrow(&this.tcx, borrow.kind));
1171                         return Control::Continue;
1172                     }
1173
1174                     match kind {
1175                         ReadKind::Copy => {
1176                             error_reported = true;
1177                             this.report_use_while_mutably_borrowed(context, place_span, borrow)
1178                         }
1179                         ReadKind::Borrow(bk) => {
1180                             error_reported = true;
1181                             this.report_conflicting_borrow(context, place_span, bk, &borrow)
1182                         }
1183                     }
1184                     Control::Break
1185                 }
1186
1187                 (Reservation(kind), BorrowKind::Unique)
1188                 | (Reservation(kind), BorrowKind::Mut { .. })
1189                 | (Activation(kind, _), _)
1190                 | (Write(kind), _) => {
1191                     match rw {
1192                         Reservation(_) => {
1193                             debug!(
1194                                 "recording invalid reservation of \
1195                                  place: {:?}",
1196                                 place_span.0
1197                             );
1198                             this.reservation_error_reported.insert(place_span.0.clone());
1199                         }
1200                         Activation(_, activating) => {
1201                             debug!(
1202                                 "observing check_place for activation of \
1203                                  borrow_index: {:?}",
1204                                 activating
1205                             );
1206                         }
1207                         Read(..) | Write(..) => {}
1208                     }
1209
1210                     match kind {
1211                         WriteKind::MutableBorrow(bk) => {
1212                             error_reported = true;
1213                             this.report_conflicting_borrow(context, place_span, bk, &borrow)
1214                         }
1215                         WriteKind::StorageDeadOrDrop => {
1216                             error_reported = true;
1217                             this.report_borrowed_value_does_not_live_long_enough(
1218                                 context,
1219                                 borrow,
1220                                 place_span,
1221                                 Some(kind),
1222                             );
1223                         }
1224                         WriteKind::Mutate => {
1225                             error_reported = true;
1226                             this.report_illegal_mutation_of_borrowed(context, place_span, borrow)
1227                         }
1228                         WriteKind::Move => {
1229                             error_reported = true;
1230                             this.report_move_out_while_borrowed(context, place_span, &borrow)
1231                         }
1232                     }
1233                     Control::Break
1234                 }
1235             },
1236         );
1237
1238         error_reported
1239     }
1240
1241     fn mutate_place(
1242         &mut self,
1243         context: Context,
1244         place_span: (&Place<'tcx>, Span),
1245         kind: ShallowOrDeep,
1246         mode: MutateMode,
1247         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1248     ) {
1249         // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
1250         match mode {
1251             MutateMode::WriteAndRead => {
1252                 self.check_if_path_or_subpath_is_moved(
1253                     context,
1254                     InitializationRequiringAction::Update,
1255                     place_span,
1256                     flow_state,
1257                 );
1258             }
1259             MutateMode::JustWrite => {
1260                 self.check_if_assigned_path_is_moved(context, place_span, flow_state);
1261             }
1262         }
1263
1264         // Special case: you can assign a immutable local variable
1265         // (e.g., `x = ...`) so long as it has never been initialized
1266         // before (at this point in the flow).
1267         if let &Place::Local(local) = place_span.0 {
1268             if let Mutability::Not = self.mir.local_decls[local].mutability {
1269                 // check for reassignments to immutable local variables
1270                 self.check_if_reassignment_to_immutable_state(
1271                     context,
1272                     local,
1273                     place_span,
1274                     flow_state,
1275                 );
1276                 return;
1277             }
1278         }
1279
1280         // Otherwise, use the normal access permission rules.
1281         self.access_place(
1282             context,
1283             place_span,
1284             (kind, Write(WriteKind::Mutate)),
1285             LocalMutationIsAllowed::No,
1286             flow_state,
1287         );
1288     }
1289
1290     fn consume_rvalue(
1291         &mut self,
1292         context: Context,
1293         (rvalue, span): (&Rvalue<'tcx>, Span),
1294         _location: Location,
1295         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1296     ) {
1297         match *rvalue {
1298             Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
1299                 let access_kind = match bk {
1300                     BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
1301                     BorrowKind::Unique | BorrowKind::Mut { .. } => {
1302                         let wk = WriteKind::MutableBorrow(bk);
1303                         if allow_two_phase_borrow(&self.tcx, bk) {
1304                             (Deep, Reservation(wk))
1305                         } else {
1306                             (Deep, Write(wk))
1307                         }
1308                     }
1309                 };
1310
1311                 self.access_place(
1312                     context,
1313                     (place, span),
1314                     access_kind,
1315                     LocalMutationIsAllowed::No,
1316                     flow_state,
1317                 );
1318
1319                 self.check_if_path_or_subpath_is_moved(
1320                     context,
1321                     InitializationRequiringAction::Borrow,
1322                     (place, span),
1323                     flow_state,
1324                 );
1325             }
1326
1327             Rvalue::Use(ref operand)
1328             | Rvalue::Repeat(ref operand, _)
1329             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
1330             | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
1331                 self.consume_operand(context, (operand, span), flow_state)
1332             }
1333
1334             Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
1335                 let af = match *rvalue {
1336                     Rvalue::Len(..) => ArtificialField::ArrayLength,
1337                     Rvalue::Discriminant(..) => ArtificialField::Discriminant,
1338                     _ => unreachable!(),
1339                 };
1340                 self.access_place(
1341                     context,
1342                     (place, span),
1343                     (Shallow(Some(af)), Read(ReadKind::Copy)),
1344                     LocalMutationIsAllowed::No,
1345                     flow_state,
1346                 );
1347                 self.check_if_path_or_subpath_is_moved(
1348                     context,
1349                     InitializationRequiringAction::Use,
1350                     (place, span),
1351                     flow_state,
1352                 );
1353             }
1354
1355             Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
1356             | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
1357                 self.consume_operand(context, (operand1, span), flow_state);
1358                 self.consume_operand(context, (operand2, span), flow_state);
1359             }
1360
1361             Rvalue::NullaryOp(_op, _ty) => {
1362                 // nullary ops take no dynamic input; no borrowck effect.
1363                 //
1364                 // FIXME: is above actually true? Do we want to track
1365                 // the fact that uninitialized data can be created via
1366                 // `NullOp::Box`?
1367             }
1368
1369             Rvalue::Aggregate(ref aggregate_kind, ref operands) => {
1370                 // We need to report back the list of mutable upvars that were
1371                 // moved into the closure and subsequently used by the closure,
1372                 // in order to populate our used_mut set.
1373                 match **aggregate_kind {
1374                     AggregateKind::Closure(def_id, _)
1375                     | AggregateKind::Generator(def_id, _, _) => {
1376                         let BorrowCheckResult {
1377                             used_mut_upvars, ..
1378                         } = self.tcx.mir_borrowck(def_id);
1379                         debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1380                         for field in used_mut_upvars {
1381                             // This relies on the current way that by-value
1382                             // captures of a closure are copied/moved directly
1383                             // when generating MIR.
1384                             match operands[field.index()] {
1385                                 Operand::Move(Place::Local(local))
1386                                 | Operand::Copy(Place::Local(local)) => {
1387                                     self.used_mut.insert(local);
1388                                 }
1389                                 Operand::Move(ref place @ Place::Projection(_))
1390                                 | Operand::Copy(ref place @ Place::Projection(_)) => {
1391                                     if let Some(field) = place.is_upvar_field_projection(
1392                                             self.mir, &self.tcx) {
1393                                         self.used_mut_upvars.push(field);
1394                                     }
1395                                 }
1396                                 Operand::Move(Place::Static(..))
1397                                 | Operand::Copy(Place::Static(..))
1398                                 | Operand::Move(Place::Promoted(..))
1399                                 | Operand::Copy(Place::Promoted(..))
1400                                 | Operand::Constant(..) => {}
1401                             }
1402                         }
1403                     }
1404                     AggregateKind::Adt(..)
1405                     | AggregateKind::Array(..)
1406                     | AggregateKind::Tuple { .. } => (),
1407                 }
1408
1409                 for operand in operands {
1410                     self.consume_operand(context, (operand, span), flow_state);
1411                 }
1412             }
1413         }
1414     }
1415
1416     fn consume_operand(
1417         &mut self,
1418         context: Context,
1419         (operand, span): (&Operand<'tcx>, Span),
1420         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1421     ) {
1422         match *operand {
1423             Operand::Copy(ref place) => {
1424                 // copy of place: check if this is "copy of frozen path"
1425                 // (FIXME: see check_loans.rs)
1426                 self.access_place(
1427                     context,
1428                     (place, span),
1429                     (Deep, Read(ReadKind::Copy)),
1430                     LocalMutationIsAllowed::No,
1431                     flow_state,
1432                 );
1433
1434                 // Finally, check if path was already moved.
1435                 self.check_if_path_or_subpath_is_moved(
1436                     context,
1437                     InitializationRequiringAction::Use,
1438                     (place, span),
1439                     flow_state,
1440                 );
1441             }
1442             Operand::Move(ref place) => {
1443                 // move of place: check if this is move of already borrowed path
1444                 self.access_place(
1445                     context,
1446                     (place, span),
1447                     (Deep, Write(WriteKind::Move)),
1448                     LocalMutationIsAllowed::Yes,
1449                     flow_state,
1450                 );
1451
1452                 // Finally, check if path was already moved.
1453                 self.check_if_path_or_subpath_is_moved(
1454                     context,
1455                     InitializationRequiringAction::Use,
1456                     (place, span),
1457                     flow_state,
1458                 );
1459             }
1460             Operand::Constant(_) => {}
1461         }
1462     }
1463
1464     /// Returns whether a borrow of this place is invalidated when the function
1465     /// exits
1466     fn check_for_invalidation_at_exit(
1467         &mut self,
1468         context: Context,
1469         borrow: &BorrowData<'tcx>,
1470         span: Span,
1471     ) {
1472         debug!("check_for_invalidation_at_exit({:?})", borrow);
1473         let place = &borrow.borrowed_place;
1474         let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
1475
1476         // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
1477         // we just know that all locals are dropped at function exit (otherwise
1478         // we'll have a memory leak) and assume that all statics have a destructor.
1479         //
1480         // FIXME: allow thread-locals to borrow other thread locals?
1481         let (might_be_alive, will_be_dropped) = match root_place {
1482             Place::Promoted(_) => (true, false),
1483             Place::Static(_) => {
1484                 // Thread-locals might be dropped after the function exits, but
1485                 // "true" statics will never be.
1486                 let is_thread_local = self.is_place_thread_local(&root_place);
1487                 (true, is_thread_local)
1488             }
1489             Place::Local(_) => {
1490                 // Locals are always dropped at function exit, and if they
1491                 // have a destructor it would've been called already.
1492                 (false, self.locals_are_invalidated_at_exit)
1493             }
1494             Place::Projection(..) => {
1495                 bug!("root of {:?} is a projection ({:?})?", place, root_place)
1496             }
1497         };
1498
1499         if !will_be_dropped {
1500             debug!(
1501                 "place_is_invalidated_at_exit({:?}) - won't be dropped",
1502                 place
1503             );
1504             return;
1505         }
1506
1507         // FIXME: replace this with a proper borrow_conflicts_with_place when
1508         // that is merged.
1509         let sd = if might_be_alive { Deep } else { Shallow(None) };
1510
1511         if places_conflict::places_conflict(self.tcx, self.mir, place, root_place, sd) {
1512             debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1513             // FIXME: should be talking about the region lifetime instead
1514             // of just a span here.
1515             let span = self.tcx.sess.source_map().end_point(span);
1516             self.report_borrowed_value_does_not_live_long_enough(
1517                 context,
1518                 borrow,
1519                 (place, span),
1520                 None,
1521             )
1522         }
1523     }
1524
1525     /// Reports an error if this is a borrow of local data.
1526     /// This is called for all Yield statements on movable generators
1527     fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1528         debug!("check_for_local_borrow({:?})", borrow);
1529
1530         if borrow_of_local_data(&borrow.borrowed_place) {
1531             let err = self.tcx
1532                 .cannot_borrow_across_generator_yield(
1533                     self.retrieve_borrow_spans(borrow).var_or_use(),
1534                     yield_span,
1535                     Origin::Mir,
1536                 );
1537
1538             err.buffer(&mut self.errors_buffer);
1539         }
1540     }
1541
1542     fn check_activations(
1543         &mut self,
1544         location: Location,
1545         span: Span,
1546         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1547     ) {
1548         if !self.tcx.two_phase_borrows() {
1549             return;
1550         }
1551
1552         // Two-phase borrow support: For each activation that is newly
1553         // generated at this statement, check if it interferes with
1554         // another borrow.
1555         let borrow_set = self.borrow_set.clone();
1556         for &borrow_index in borrow_set.activations_at_location(location) {
1557             let borrow = &borrow_set[borrow_index];
1558
1559             // only mutable borrows should be 2-phase
1560             assert!(match borrow.kind {
1561                 BorrowKind::Shared => false,
1562                 BorrowKind::Unique | BorrowKind::Mut { .. } => true,
1563             });
1564
1565             self.access_place(
1566                 ContextKind::Activation.new(location),
1567                 (&borrow.borrowed_place, span),
1568                 (
1569                     Deep,
1570                     Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index),
1571                 ),
1572                 LocalMutationIsAllowed::No,
1573                 flow_state,
1574             );
1575             // We do not need to call `check_if_path_or_subpath_is_moved`
1576             // again, as we already called it when we made the
1577             // initial reservation.
1578         }
1579     }
1580 }
1581
1582 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1583     fn check_if_reassignment_to_immutable_state(
1584         &mut self,
1585         context: Context,
1586         local: Local,
1587         place_span: (&Place<'tcx>, Span),
1588         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1589     ) {
1590         debug!("check_if_reassignment_to_immutable_state({:?})", local);
1591
1592         // Check if any of the initializiations of `local` have happened yet:
1593         let mpi = self.move_data.rev_lookup.find_local(local);
1594         let init_indices = &self.move_data.init_path_map[mpi];
1595         let first_init_index = init_indices.iter().find(|ii| flow_state.ever_inits.contains(ii));
1596         if let Some(&init_index) = first_init_index {
1597             // And, if so, report an error.
1598             let init = &self.move_data.inits[init_index];
1599             self.report_illegal_reassignment(context, place_span, init.span, place_span.0);
1600         }
1601     }
1602
1603     fn check_if_full_path_is_moved(
1604         &mut self,
1605         context: Context,
1606         desired_action: InitializationRequiringAction,
1607         place_span: (&Place<'tcx>, Span),
1608         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1609     ) {
1610         // FIXME: analogous code in check_loans first maps `place` to
1611         // its base_path ... but is that what we want here?
1612         let place = self.base_path(place_span.0);
1613
1614         let maybe_uninits = &flow_state.uninits;
1615         let curr_move_outs = &flow_state.move_outs;
1616
1617         // Bad scenarios:
1618         //
1619         // 1. Move of `a.b.c`, use of `a.b.c`
1620         // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`)
1621         // 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
1622         //    partial initialization support, one might have `a.x`
1623         //    initialized but not `a.b`.
1624         //
1625         // OK scenarios:
1626         //
1627         // 4. Move of `a.b.c`, use of `a.b.d`
1628         // 5. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1629         // 6. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1630         //    must have been initialized for the use to be sound.
1631         // 7. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1632
1633         // The dataflow tracks shallow prefixes distinctly (that is,
1634         // field-accesses on P distinctly from P itself), in order to
1635         // track substructure initialization separately from the whole
1636         // structure.
1637         //
1638         // E.g., when looking at (*a.b.c).d, if the closest prefix for
1639         // which we have a MovePath is `a.b`, then that means that the
1640         // initialization state of `a.b` is all we need to inspect to
1641         // know if `a.b.c` is valid (and from that we infer that the
1642         // dereference and `.d` access is also valid, since we assume
1643         // `a.b.c` is assigned a reference to a initialized and
1644         // well-formed record structure.)
1645
1646         // Therefore, if we seek out the *closest* prefix for which we
1647         // have a MovePath, that should capture the initialization
1648         // state for the place scenario.
1649         //
1650         // This code covers scenarios 1, 2, and 3.
1651
1652         debug!("check_if_full_path_is_moved place: {:?}", place);
1653         match self.move_path_closest_to(place) {
1654             Ok(mpi) => {
1655                 if maybe_uninits.contains(&mpi) {
1656                     self.report_use_of_moved_or_uninitialized(
1657                         context,
1658                         desired_action,
1659                         place_span,
1660                         mpi,
1661                         curr_move_outs,
1662                     );
1663                     return; // don't bother finding other problems.
1664                 }
1665             }
1666             Err(NoMovePathFound::ReachedStatic) => {
1667                 // Okay: we do not build MoveData for static variables
1668             } // Only query longest prefix with a MovePath, not further
1669               // ancestors; dataflow recurs on children when parents
1670               // move (to support partial (re)inits).
1671               //
1672               // (I.e. querying parents breaks scenario 7; but may want
1673               // to do such a query based on partial-init feature-gate.)
1674         }
1675     }
1676
1677     fn check_if_path_or_subpath_is_moved(
1678         &mut self,
1679         context: Context,
1680         desired_action: InitializationRequiringAction,
1681         place_span: (&Place<'tcx>, Span),
1682         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1683     ) {
1684         // FIXME: analogous code in check_loans first maps `place` to
1685         // its base_path ... but is that what we want here?
1686         let place = self.base_path(place_span.0);
1687
1688         let maybe_uninits = &flow_state.uninits;
1689         let curr_move_outs = &flow_state.move_outs;
1690
1691         // Bad scenarios:
1692         //
1693         // 1. Move of `a.b.c`, use of `a` or `a.b`
1694         //    partial initialization support, one might have `a.x`
1695         //    initialized but not `a.b`.
1696         // 2. All bad scenarios from `check_if_full_path_is_moved`
1697         //
1698         // OK scenarios:
1699         //
1700         // 3. Move of `a.b.c`, use of `a.b.d`
1701         // 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1702         // 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1703         //    must have been initialized for the use to be sound.
1704         // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1705
1706         self.check_if_full_path_is_moved(context, desired_action, place_span, flow_state);
1707
1708         // A move of any shallow suffix of `place` also interferes
1709         // with an attempt to use `place`. This is scenario 3 above.
1710         //
1711         // (Distinct from handling of scenarios 1+2+4 above because
1712         // `place` does not interfere with suffixes of its prefixes,
1713         // e.g. `a.b.c` does not interfere with `a.b.d`)
1714         //
1715         // This code covers scenario 1.
1716
1717         debug!("check_if_path_or_subpath_is_moved place: {:?}", place);
1718         if let Some(mpi) = self.move_path_for_place(place) {
1719             if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) {
1720                 self.report_use_of_moved_or_uninitialized(
1721                     context,
1722                     desired_action,
1723                     place_span,
1724                     child_mpi,
1725                     curr_move_outs,
1726                 );
1727                 return; // don't bother finding other problems.
1728             }
1729         }
1730     }
1731
1732     /// Currently MoveData does not store entries for all places in
1733     /// the input MIR. For example it will currently filter out
1734     /// places that are Copy; thus we do not track places of shared
1735     /// reference type. This routine will walk up a place along its
1736     /// prefixes, searching for a foundational place that *is*
1737     /// tracked in the MoveData.
1738     ///
1739     /// An Err result includes a tag indicated why the search failed.
1740     /// Currently this can only occur if the place is built off of a
1741     /// static variable, as we do not track those in the MoveData.
1742     fn move_path_closest_to(
1743         &mut self,
1744         place: &Place<'tcx>,
1745     ) -> Result<MovePathIndex, NoMovePathFound> {
1746         let mut last_prefix = place;
1747         for prefix in self.prefixes(place, PrefixSet::All) {
1748             if let Some(mpi) = self.move_path_for_place(prefix) {
1749                 return Ok(mpi);
1750             }
1751             last_prefix = prefix;
1752         }
1753         match *last_prefix {
1754             Place::Local(_) => panic!("should have move path for every Local"),
1755             Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
1756             Place::Promoted(_) |
1757             Place::Static(_) => return Err(NoMovePathFound::ReachedStatic),
1758         }
1759     }
1760
1761     fn move_path_for_place(&mut self, place: &Place<'tcx>) -> Option<MovePathIndex> {
1762         // If returns None, then there is no move path corresponding
1763         // to a direct owner of `place` (which means there is nothing
1764         // that borrowck tracks for its analysis).
1765
1766         match self.move_data.rev_lookup.find(place) {
1767             LookupResult::Parent(_) => None,
1768             LookupResult::Exact(mpi) => Some(mpi),
1769         }
1770     }
1771
1772     fn check_if_assigned_path_is_moved(
1773         &mut self,
1774         context: Context,
1775         (place, span): (&Place<'tcx>, Span),
1776         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1777     ) {
1778         debug!("check_if_assigned_path_is_moved place: {:?}", place);
1779         // recur down place; dispatch to external checks when necessary
1780         let mut place = place;
1781         loop {
1782             match *place {
1783                 Place::Promoted(_) |
1784                 Place::Local(_) | Place::Static(_) => {
1785                     // assigning to `x` does not require `x` be initialized.
1786                     break;
1787                 }
1788                 Place::Projection(ref proj) => {
1789                     let Projection { ref base, ref elem } = **proj;
1790                     match *elem {
1791                         ProjectionElem::Index(_/*operand*/) |
1792                         ProjectionElem::ConstantIndex { .. } |
1793                         // assigning to P[i] requires P to be valid.
1794                         ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
1795                         // assigning to (P->variant) is okay if assigning to `P` is okay
1796                         //
1797                         // FIXME: is this true even if P is a adt with a dtor?
1798                         { }
1799
1800                         // assigning to (*P) requires P to be initialized
1801                         ProjectionElem::Deref => {
1802                             self.check_if_full_path_is_moved(
1803                                 context, InitializationRequiringAction::Use,
1804                                 (base, span), flow_state);
1805                             // (base initialized; no need to
1806                             // recur further)
1807                             break;
1808                         }
1809
1810                         ProjectionElem::Subslice { .. } => {
1811                             panic!("we don't allow assignments to subslices, context: {:?}",
1812                                    context);
1813                         }
1814
1815                         ProjectionElem::Field(..) => {
1816                             // if type of `P` has a dtor, then
1817                             // assigning to `P.f` requires `P` itself
1818                             // be already initialized
1819                             let tcx = self.tcx;
1820                             match base.ty(self.mir, tcx).to_ty(tcx).sty {
1821                                 ty::TyAdt(def, _) if def.has_dtor(tcx) => {
1822
1823                                     // FIXME: analogous code in
1824                                     // check_loans.rs first maps
1825                                     // `base` to its base_path.
1826
1827                                     self.check_if_path_or_subpath_is_moved(
1828                                         context, InitializationRequiringAction::Assignment,
1829                                         (base, span), flow_state);
1830
1831                                     // (base initialized; no need to
1832                                     // recur further)
1833                                     break;
1834                                 }
1835                                 _ => {}
1836                             }
1837                         }
1838                     }
1839
1840                     place = base;
1841                     continue;
1842                 }
1843             }
1844         }
1845     }
1846
1847
1848     /// Check the permissions for the given place and read or write kind
1849     ///
1850     /// Returns true if an error is reported, false otherwise.
1851     fn check_access_permissions(
1852         &mut self,
1853         (place, span): (&Place<'tcx>, Span),
1854         kind: ReadOrWrite,
1855         is_local_mutation_allowed: LocalMutationIsAllowed,
1856         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1857         location: Location,
1858     ) -> bool {
1859         debug!(
1860             "check_access_permissions({:?}, {:?}, {:?})",
1861             place, kind, is_local_mutation_allowed
1862         );
1863
1864         let error_access;
1865         let the_place_err;
1866
1867         match kind {
1868             Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
1869             | Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. }))
1870             | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
1871             | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => {
1872                 let is_local_mutation_allowed = match borrow_kind {
1873                     BorrowKind::Unique => LocalMutationIsAllowed::Yes,
1874                     BorrowKind::Mut { .. } => is_local_mutation_allowed,
1875                     BorrowKind::Shared => unreachable!(),
1876                 };
1877                 match self.is_mutable(place, is_local_mutation_allowed) {
1878                     Ok(root_place) => {
1879                         self.add_used_mut(root_place, flow_state);
1880                         return false;
1881                     }
1882                     Err(place_err) => {
1883                         error_access = AccessKind::MutableBorrow;
1884                         the_place_err = place_err;
1885                     }
1886                 }
1887             }
1888             Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
1889                 match self.is_mutable(place, is_local_mutation_allowed) {
1890                     Ok(root_place) => {
1891                         self.add_used_mut(root_place, flow_state);
1892                         return false;
1893                     }
1894                     Err(place_err) => {
1895                         error_access = AccessKind::Mutate;
1896                         the_place_err = place_err;
1897                     }
1898                 }
1899             }
1900
1901             Reservation(wk @ WriteKind::Move)
1902             | Write(wk @ WriteKind::Move)
1903             | Reservation(wk @ WriteKind::StorageDeadOrDrop)
1904             | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
1905             | Write(wk @ WriteKind::StorageDeadOrDrop)
1906             | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => {
1907                 if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
1908                     if self.tcx.migrate_borrowck() {
1909                         // rust-lang/rust#46908: In pure NLL mode this
1910                         // code path should be unreachable (and thus
1911                         // we signal an ICE in the else branch
1912                         // here). But we can legitimately get here
1913                         // under borrowck=migrate mode, so instead of
1914                         // ICE'ing we instead report a legitimate
1915                         // error (which will then be downgraded to a
1916                         // warning by the migrate machinery).
1917                         error_access = match wk {
1918                             WriteKind::MutableBorrow(_) => AccessKind::MutableBorrow,
1919                             WriteKind::Move => AccessKind::Move,
1920                             WriteKind::StorageDeadOrDrop |
1921                             WriteKind::Mutate => AccessKind::Mutate,
1922                         };
1923                         self.report_mutability_error(
1924                             place,
1925                             span,
1926                             _place_err,
1927                             error_access,
1928                             location,
1929                         );
1930                     } else {
1931                         self.tcx.sess.delay_span_bug(
1932                             span,
1933                             &format!(
1934                                 "Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
1935                                 place, kind
1936                             ),
1937                         );
1938                     }
1939                 }
1940                 return false;
1941             }
1942             Activation(..) => {
1943                 // permission checks are done at Reservation point.
1944                 return false;
1945             }
1946             Read(ReadKind::Borrow(BorrowKind::Unique))
1947             | Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
1948             | Read(ReadKind::Borrow(BorrowKind::Shared))
1949             | Read(ReadKind::Copy) => {
1950                 // Access authorized
1951                 return false;
1952             }
1953         }
1954
1955         // at this point, we have set up the error reporting state.
1956         self.report_mutability_error(
1957             place,
1958             span,
1959             the_place_err,
1960             error_access,
1961             location,
1962         );
1963         return true;
1964     }
1965
1966     /// Adds the place into the used mutable variables set
1967     fn add_used_mut<'d>(
1968         &mut self,
1969         root_place: RootPlace<'d, 'tcx>,
1970         flow_state: &Flows<'cx, 'gcx, 'tcx>,
1971     ) {
1972         match root_place {
1973             RootPlace {
1974                 place: Place::Local(local),
1975                 is_local_mutation_allowed,
1976             } => {
1977                 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes {
1978                     // If the local may be initialized, and it is now currently being
1979                     // mutated, then it is justified to be annotated with the `mut`
1980                     // keyword, since the mutation may be a possible reassignment.
1981                     let mpi = self.move_data.rev_lookup.find_local(*local);
1982                     let ii = &self.move_data.init_path_map[mpi];
1983                     for index in ii {
1984                         if flow_state.ever_inits.contains(index) {
1985                             self.used_mut.insert(*local);
1986                             break;
1987                         }
1988                     }
1989                 }
1990             }
1991             RootPlace {
1992                 place: _,
1993                 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
1994             } => {}
1995             RootPlace {
1996                 place: place @ Place::Projection(_),
1997                 is_local_mutation_allowed: _,
1998             } => {
1999                 if let Some(field) = place.is_upvar_field_projection(self.mir, &self.tcx) {
2000                     self.used_mut_upvars.push(field);
2001                 }
2002             }
2003             RootPlace {
2004                 place: Place::Promoted(..),
2005                 is_local_mutation_allowed: _,
2006             } => {}
2007             RootPlace {
2008                 place: Place::Static(..),
2009                 is_local_mutation_allowed: _,
2010             } => {}
2011         }
2012     }
2013
2014     /// Whether this value be written or borrowed mutably.
2015     /// Returns the root place if the place passed in is a projection.
2016     fn is_mutable<'d>(
2017         &self,
2018         place: &'d Place<'tcx>,
2019         is_local_mutation_allowed: LocalMutationIsAllowed,
2020     ) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> {
2021         match *place {
2022             Place::Local(local) => {
2023                 let local = &self.mir.local_decls[local];
2024                 match local.mutability {
2025                     Mutability::Not => match is_local_mutation_allowed {
2026                         LocalMutationIsAllowed::Yes => Ok(RootPlace {
2027                             place,
2028                             is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2029                         }),
2030                         LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2031                             place,
2032                             is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2033                         }),
2034                         LocalMutationIsAllowed::No => Err(place),
2035                     },
2036                     Mutability::Mut => Ok(RootPlace {
2037                         place,
2038                         is_local_mutation_allowed,
2039                     }),
2040                 }
2041             }
2042             // The rules for promotion are made by `qualify_consts`, there wouldn't even be a
2043             // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
2044             Place::Promoted(_) => Ok(RootPlace {
2045                 place,
2046                 is_local_mutation_allowed,
2047             }),
2048             Place::Static(ref static_) => {
2049                 if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
2050                     Err(place)
2051                 } else {
2052                     Ok(RootPlace {
2053                         place,
2054                         is_local_mutation_allowed,
2055                     })
2056                 }
2057             }
2058             Place::Projection(ref proj) => {
2059                 match proj.elem {
2060                     ProjectionElem::Deref => {
2061                         let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
2062
2063                         // Check the kind of deref to decide
2064                         match base_ty.sty {
2065                             ty::TyRef(_, _, mutbl) => {
2066                                 match mutbl {
2067                                     // Shared borrowed data is never mutable
2068                                     hir::MutImmutable => Err(place),
2069                                     // Mutably borrowed data is mutable, but only if we have a
2070                                     // unique path to the `&mut`
2071                                     hir::MutMutable => {
2072                                         let mode = match place.is_upvar_field_projection(
2073                                             self.mir, &self.tcx)
2074                                         {
2075                                             Some(field)
2076                                                 if {
2077                                                     self.mir.upvar_decls[field.index()].by_ref
2078                                                 } =>
2079                                             {
2080                                                 is_local_mutation_allowed
2081                                             }
2082                                             _ => LocalMutationIsAllowed::Yes,
2083                                         };
2084
2085                                         self.is_mutable(&proj.base, mode)
2086                                     }
2087                                 }
2088                             }
2089                             ty::TyRawPtr(tnm) => {
2090                                 match tnm.mutbl {
2091                                     // `*const` raw pointers are not mutable
2092                                     hir::MutImmutable => return Err(place),
2093                                     // `*mut` raw pointers are always mutable, regardless of
2094                                     // context. The users have to check by themselves.
2095                                     hir::MutMutable => {
2096                                         return Ok(RootPlace {
2097                                             place,
2098                                             is_local_mutation_allowed,
2099                                         });
2100                                     }
2101                                 }
2102                             }
2103                             // `Box<T>` owns its content, so mutable if its location is mutable
2104                             _ if base_ty.is_box() => {
2105                                 self.is_mutable(&proj.base, is_local_mutation_allowed)
2106                             }
2107                             // Deref should only be for reference, pointers or boxes
2108                             _ => bug!("Deref of unexpected type: {:?}", base_ty),
2109                         }
2110                     }
2111                     // All other projections are owned by their base path, so mutable if
2112                     // base path is mutable
2113                     ProjectionElem::Field(..)
2114                     | ProjectionElem::Index(..)
2115                     | ProjectionElem::ConstantIndex { .. }
2116                     | ProjectionElem::Subslice { .. }
2117                     | ProjectionElem::Downcast(..) => {
2118                         let upvar_field_projection = place.is_upvar_field_projection(
2119                             self.mir, &self.tcx);
2120                         if let Some(field) = upvar_field_projection {
2121                             let decl = &self.mir.upvar_decls[field.index()];
2122                             debug!(
2123                                 "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
2124                                 decl, is_local_mutation_allowed, place
2125                             );
2126                             match (decl.mutability, is_local_mutation_allowed) {
2127                                 (Mutability::Not, LocalMutationIsAllowed::No)
2128                                 | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => {
2129                                     Err(place)
2130                                 }
2131                                 (Mutability::Not, LocalMutationIsAllowed::Yes)
2132                                 | (Mutability::Mut, _) => {
2133                                     // Subtle: this is an upvar
2134                                     // reference, so it looks like
2135                                     // `self.foo` -- we want to double
2136                                     // check that the context `*self`
2137                                     // is mutable (i.e., this is not a
2138                                     // `Fn` closure).  But if that
2139                                     // check succeeds, we want to
2140                                     // *blame* the mutability on
2141                                     // `place` (that is,
2142                                     // `self.foo`). This is used to
2143                                     // propagate the info about
2144                                     // whether mutability declarations
2145                                     // are used outwards, so that we register
2146                                     // the outer variable as mutable. Otherwise a
2147                                     // test like this fails to record the `mut`
2148                                     // as needed:
2149                                     //
2150                                     // ```
2151                                     // fn foo<F: FnOnce()>(_f: F) { }
2152                                     // fn main() {
2153                                     //     let var = Vec::new();
2154                                     //     foo(move || {
2155                                     //         var.push(1);
2156                                     //     });
2157                                     // }
2158                                     // ```
2159                                     let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?;
2160                                     Ok(RootPlace {
2161                                         place,
2162                                         is_local_mutation_allowed,
2163                                     })
2164                                 }
2165                             }
2166                         } else {
2167                             self.is_mutable(&proj.base, is_local_mutation_allowed)
2168                         }
2169                     }
2170                 }
2171             }
2172         }
2173     }
2174 }
2175
2176 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2177 enum NoMovePathFound {
2178     ReachedStatic,
2179 }
2180
2181 /// The degree of overlap between 2 places for borrow-checking.
2182 enum Overlap {
2183     /// The places might partially overlap - in this case, we give
2184     /// up and say that they might conflict. This occurs when
2185     /// different fields of a union are borrowed. For example,
2186     /// if `u` is a union, we have no way of telling how disjoint
2187     /// `u.a.x` and `a.b.y` are.
2188     Arbitrary,
2189     /// The places have the same type, and are either completely disjoint
2190     /// or equal - i.e. they can't "partially" overlap as can occur with
2191     /// unions. This is the "base case" on which we recur for extensions
2192     /// of the place.
2193     EqualOrDisjoint,
2194     /// The places are disjoint, so we know all extensions of them
2195     /// will also be disjoint.
2196     Disjoint,
2197 }
2198
2199 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2200     // FIXME (#16118): function intended to allow the borrow checker
2201     // to be less precise in its handling of Box while still allowing
2202     // moves out of a Box. They should be removed when/if we stop
2203     // treating Box specially (e.g. when/if DerefMove is added...)
2204
2205     fn base_path<'d>(&self, place: &'d Place<'tcx>) -> &'d Place<'tcx> {
2206         //! Returns the base of the leftmost (deepest) dereference of an
2207         //! Box in `place`. If there is no dereference of an Box
2208         //! in `place`, then it just returns `place` itself.
2209
2210         let mut cursor = place;
2211         let mut deepest = place;
2212         loop {
2213             let proj = match *cursor {
2214                 Place::Promoted(_) |
2215                 Place::Local(..) | Place::Static(..) => return deepest,
2216                 Place::Projection(ref proj) => proj,
2217             };
2218             if proj.elem == ProjectionElem::Deref
2219                 && place.ty(self.mir, self.tcx).to_ty(self.tcx).is_box()
2220             {
2221                 deepest = &proj.base;
2222             }
2223             cursor = &proj.base;
2224         }
2225     }
2226 }
2227
2228 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2229 struct Context {
2230     kind: ContextKind,
2231     loc: Location,
2232 }
2233
2234 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2235 enum ContextKind {
2236     Activation,
2237     AssignLhs,
2238     AssignRhs,
2239     SetDiscrim,
2240     InlineAsm,
2241     SwitchInt,
2242     Drop,
2243     DropAndReplace,
2244     CallOperator,
2245     CallOperand,
2246     CallDest,
2247     Assert,
2248     Yield,
2249     ReadForMatch,
2250     StorageDead,
2251 }
2252
2253 impl ContextKind {
2254     fn new(self, loc: Location) -> Context {
2255         Context {
2256             kind: self,
2257             loc: loc,
2258         }
2259     }
2260 }