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