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