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