]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/error_reporting.rs
73fdb4bd5d17b19f9f45af475c83d67302f76e4b
[rust.git] / src / librustc_mir / borrow_check / error_reporting.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 use borrow_check::{WriteKind, StorageDeadOrDrop};
12 use borrow_check::prefixes::IsPrefixOf;
13 use borrow_check::nll::explain_borrow::BorrowExplanation;
14 use rustc::middle::region::ScopeTree;
15 use rustc::mir::{
16     AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local,
17     LocalDecl, LocalKind, Location, Operand, Place, ProjectionElem, Rvalue, Statement,
18     StatementKind, VarBindingForm,
19 };
20 use rustc::hir::def_id::DefId;
21 use rustc::ty;
22 use rustc_data_structures::fx::FxHashSet;
23 use rustc_data_structures::sync::Lrc;
24 use rustc_errors::{Applicability, DiagnosticBuilder};
25 use rustc::util::ppaux::with_highlight_region_for_bound_region;
26 use syntax_pos::Span;
27
28 use super::borrow_set::BorrowData;
29 use super::{Context, MirBorrowckCtxt};
30 use super::{InitializationRequiringAction, PrefixSet};
31
32 use dataflow::drop_flag_effects;
33 use dataflow::move_paths::indexes::MoveOutIndex;
34 use dataflow::move_paths::MovePathIndex;
35 use util::borrowck_errors::{BorrowckErrors, Origin};
36
37 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
38     pub(super) fn report_use_of_moved_or_uninitialized(
39         &mut self,
40         context: Context,
41         desired_action: InitializationRequiringAction,
42         (place, span): (&Place<'tcx>, Span),
43         mpi: MovePathIndex,
44     ) {
45         debug!(
46             "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} place={:?} \
47             span={:?} mpi={:?}",
48             context, desired_action, place, span, mpi
49         );
50
51         let use_spans = self
52             .move_spans(place, context.loc)
53             .or_else(|| self.borrow_spans(span, context.loc));
54         let span = use_spans.args_or_use();
55
56         let mois = self.get_moved_indexes(context, mpi);
57         debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
58
59         if mois.is_empty() {
60             let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
61
62             if self.uninitialized_error_reported.contains(&root_place.clone()) {
63                 debug!(
64                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
65                     root_place
66                 );
67                 return;
68             }
69
70             self.uninitialized_error_reported.insert(root_place.clone());
71
72             let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
73                 Some(name) => format!("`{}`", name),
74                 None => "value".to_owned(),
75             };
76             let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
77                 span,
78                 desired_action.as_noun(),
79                 &self
80                     .describe_place_with_options(place, IncludingDowncast(true))
81                     .unwrap_or("_".to_owned()),
82                 Origin::Mir,
83             );
84             err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
85
86             use_spans.var_span_label(
87                 &mut err,
88                 format!("{} occurs due to use in closure", desired_action.as_noun()),
89             );
90
91             err.buffer(&mut self.errors_buffer);
92         } else {
93             if let Some((reported_place, _)) = self.move_error_reported.get(&mois) {
94                 if self.prefixes(&reported_place, PrefixSet::All).any(|p| p == place) {
95                     debug!("report_use_of_moved_or_uninitialized place: error suppressed \
96                            mois={:?}", mois);
97                     return;
98                 }
99             }
100
101             let msg = ""; //FIXME: add "partially " or "collaterally "
102
103             let mut err = self.infcx.tcx.cannot_act_on_moved_value(
104                 span,
105                 desired_action.as_noun(),
106                 msg,
107                 self.describe_place_with_options(&place, IncludingDowncast(true)),
108                 Origin::Mir,
109             );
110
111             let mut is_loop_move = false;
112             for moi in &mois {
113                 let move_out = self.move_data.moves[*moi];
114                 let moved_place = &self.move_data.move_paths[move_out.path].place;
115
116                 let move_spans = self.move_spans(moved_place, move_out.source);
117                 let move_span = move_spans.args_or_use();
118
119                 let move_msg = if move_spans.for_closure() {
120                     " into closure"
121                 } else {
122                     ""
123                 };
124
125                 if span == move_span {
126                     err.span_label(
127                         span,
128                         format!("value moved{} here in previous iteration of loop", move_msg),
129                     );
130                     is_loop_move = true;
131                 } else {
132                     err.span_label(move_span, format!("value moved{} here", move_msg));
133                     move_spans.var_span_label(&mut err, "variable moved due to use in closure");
134                 };
135             }
136
137             use_spans.var_span_label(
138                 &mut err,
139                 format!("{} occurs due to use in closure", desired_action.as_noun()),
140             );
141
142             if !is_loop_move {
143                 err.span_label(
144                     span,
145                     format!(
146                         "value {} here after move",
147                         desired_action.as_verb_in_past_tense()
148                     ),
149                 );
150             }
151
152             if let Some(ty) = self.retrieve_type_for_place(place) {
153                 let needs_note = match ty.sty {
154                     ty::Closure(id, _) => {
155                         let tables = self.infcx.tcx.typeck_tables_of(id);
156                         let node_id = self.infcx.tcx.hir.as_local_node_id(id).unwrap();
157                         let hir_id = self.infcx.tcx.hir.node_to_hir_id(node_id);
158                         if tables.closure_kind_origins().get(hir_id).is_some() {
159                             false
160                         } else {
161                             true
162                         }
163                     }
164                     _ => true,
165                 };
166
167                 if needs_note {
168                     let mpi = self.move_data.moves[mois[0]].path;
169                     let place = &self.move_data.move_paths[mpi].place;
170
171                     if let Some(ty) = self.retrieve_type_for_place(place) {
172                         let note_msg = match self
173                             .describe_place_with_options(place, IncludingDowncast(true))
174                         {
175                             Some(name) => format!("`{}`", name),
176                             None => "value".to_owned(),
177                         };
178
179                         err.note(&format!(
180                             "move occurs because {} has type `{}`, \
181                              which does not implement the `Copy` trait",
182                             note_msg, ty
183                         ));
184                     }
185                 }
186             }
187
188             if let Some((_, mut old_err)) = self.move_error_reported.insert(
189                 mois,
190                 (place.clone(), err)
191             ) {
192                 // Cancel the old error so it doesn't ICE.
193                 old_err.cancel();
194             }
195         }
196     }
197
198     pub(super) fn report_move_out_while_borrowed(
199         &mut self,
200         context: Context,
201         (place, _span): (&Place<'tcx>, Span),
202         borrow: &BorrowData<'tcx>,
203     ) {
204         let tcx = self.infcx.tcx;
205         let value_msg = match self.describe_place(place) {
206             Some(name) => format!("`{}`", name),
207             None => "value".to_owned(),
208         };
209         let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
210             Some(name) => format!("`{}`", name),
211             None => "value".to_owned(),
212         };
213
214         let borrow_spans = self.retrieve_borrow_spans(borrow);
215         let borrow_span = borrow_spans.args_or_use();
216
217         let move_spans = self.move_spans(place, context.loc);
218         let span = move_spans.args_or_use();
219
220         let mut err = tcx.cannot_move_when_borrowed(
221             span,
222             &self.describe_place(place).unwrap_or("_".to_owned()),
223             Origin::Mir,
224         );
225         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
226         err.span_label(span, format!("move out of {} occurs here", value_msg));
227
228         borrow_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
229
230         move_spans.var_span_label(&mut err, "move occurs due to use in closure");
231
232         self.explain_why_borrow_contains_point(context, borrow, None)
233             .emit(self.infcx.tcx, &mut err);
234         err.buffer(&mut self.errors_buffer);
235     }
236
237     pub(super) fn report_use_while_mutably_borrowed(
238         &mut self,
239         context: Context,
240         (place, _span): (&Place<'tcx>, Span),
241         borrow: &BorrowData<'tcx>,
242     ) {
243         let tcx = self.infcx.tcx;
244
245         let borrow_spans = self.retrieve_borrow_spans(borrow);
246         let borrow_span = borrow_spans.args_or_use();
247
248         // Conflicting borrows are reported separately, so only check for move
249         // captures.
250         let use_spans = self.move_spans(place, context.loc);
251         let span = use_spans.var_or_use();
252
253         let mut err = tcx.cannot_use_when_mutably_borrowed(
254             span,
255             &self.describe_place(place).unwrap_or("_".to_owned()),
256             borrow_span,
257             &self
258                 .describe_place(&borrow.borrowed_place)
259                 .unwrap_or("_".to_owned()),
260             Origin::Mir,
261         );
262
263         borrow_spans.var_span_label(&mut err, {
264             let place = &borrow.borrowed_place;
265             let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
266
267             format!("borrow occurs due to use of `{}` in closure", desc_place)
268         });
269
270         self.explain_why_borrow_contains_point(context, borrow, None)
271             .emit(self.infcx.tcx, &mut err);
272         err.buffer(&mut self.errors_buffer);
273     }
274
275     pub(super) fn report_conflicting_borrow(
276         &mut self,
277         context: Context,
278         (place, span): (&Place<'tcx>, Span),
279         gen_borrow_kind: BorrowKind,
280         issued_borrow: &BorrowData<'tcx>,
281     ) {
282         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
283         let issued_span = issued_spans.args_or_use();
284
285         let borrow_spans = self.borrow_spans(span, context.loc);
286         let span = borrow_spans.args_or_use();
287
288         let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
289         let tcx = self.infcx.tcx;
290
291         // FIXME: supply non-"" `opt_via` when appropriate
292         let mut err = match (
293             gen_borrow_kind,
294             "immutable",
295             "mutable",
296             issued_borrow.kind,
297             "immutable",
298             "mutable",
299         ) {
300             (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
301             | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
302                 .cannot_reborrow_already_borrowed(
303                     span,
304                     &desc_place,
305                     "",
306                     lft,
307                     issued_span,
308                     "it",
309                     rgt,
310                     "",
311                     None,
312                     Origin::Mir,
313                 ),
314
315             (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
316                 .cannot_mutably_borrow_multiply(
317                     span,
318                     &desc_place,
319                     "",
320                     issued_span,
321                     "",
322                     None,
323                     Origin::Mir,
324                 ),
325
326             (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
327                 .cannot_uniquely_borrow_by_two_closures(
328                     span,
329                     &desc_place,
330                     issued_span,
331                     None,
332                     Origin::Mir,
333                 ),
334
335             (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
336                 span,
337                 &desc_place,
338                 "",
339                 issued_span,
340                 "it",
341                 "",
342                 None,
343                 Origin::Mir,
344             ),
345
346             (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
347                 .cannot_reborrow_already_uniquely_borrowed(
348                     span,
349                     &desc_place,
350                     "",
351                     lft,
352                     issued_span,
353                     "",
354                     None,
355                     Origin::Mir,
356                 ),
357
358             (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
359                 .cannot_reborrow_already_uniquely_borrowed(
360                     span,
361                     &desc_place,
362                     "",
363                     lft,
364                     issued_span,
365                     "",
366                     None,
367                     Origin::Mir,
368                 ),
369
370             (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
371         };
372
373         if issued_spans == borrow_spans {
374             borrow_spans.var_span_label(
375                 &mut err,
376                 format!("borrows occur due to use of `{}` in closure", desc_place),
377             );
378         } else {
379             let borrow_place = &issued_borrow.borrowed_place;
380             let borrow_place_desc = self.describe_place(borrow_place).unwrap_or("_".to_owned());
381             issued_spans.var_span_label(
382                 &mut err,
383                 format!(
384                     "first borrow occurs due to use of `{}` in closure",
385                     borrow_place_desc
386                 ),
387             );
388
389             borrow_spans.var_span_label(
390                 &mut err,
391                 format!(
392                     "second borrow occurs due to use of `{}` in closure",
393                     desc_place
394                 ),
395             );
396         }
397
398         self.explain_why_borrow_contains_point(context, issued_borrow, None)
399             .emit(self.infcx.tcx, &mut err);
400
401         err.buffer(&mut self.errors_buffer);
402     }
403
404     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
405     ///
406     /// This means that some data referenced by `borrow` needs to live
407     /// past the point where the StorageDeadOrDrop of `place` occurs.
408     /// This is usually interpreted as meaning that `place` has too
409     /// short a lifetime. (But sometimes it is more useful to report
410     /// it as a more direct conflict between the execution of a
411     /// `Drop::drop` with an aliasing borrow.)
412     pub(super) fn report_borrowed_value_does_not_live_long_enough(
413         &mut self,
414         context: Context,
415         borrow: &BorrowData<'tcx>,
416         place_span: (&Place<'tcx>, Span),
417         kind: Option<WriteKind>,
418     ) {
419         debug!("report_borrowed_value_does_not_live_long_enough(\
420                 {:?}, {:?}, {:?}, {:?}\
421                 )",
422                context, borrow, place_span, kind
423         );
424
425         let drop_span = place_span.1;
426         let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id);
427         let root_place = self
428             .prefixes(&borrow.borrowed_place, PrefixSet::All)
429             .last()
430             .unwrap();
431
432         let borrow_spans = self.retrieve_borrow_spans(borrow);
433         let borrow_span = borrow_spans.var_or_use();
434
435         let proper_span = match *root_place {
436             Place::Local(local) => self.mir.local_decls[local].source_info.span,
437             _ => drop_span,
438         };
439
440         if self
441             .access_place_error_reported
442             .contains(&(root_place.clone(), borrow_span))
443         {
444             debug!(
445                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
446                 borrow_span
447             );
448             return;
449         }
450
451         self.access_place_error_reported
452             .insert((root_place.clone(), borrow_span));
453
454         if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind {
455             // If a borrow of path `B` conflicts with drop of `D` (and
456             // we're not in the uninteresting case where `B` is a
457             // prefix of `D`), then report this as a more interesting
458             // destructor conflict.
459             if !borrow.borrowed_place.is_prefix_of(place_span.0) {
460                 self.report_borrow_conflicts_with_destructor(context, borrow, place_span, kind);
461                 return;
462             }
463         }
464
465         let err = match &self.describe_place(&borrow.borrowed_place) {
466             Some(_) if self.is_place_thread_local(root_place) =>
467                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span),
468             Some(name) => self.report_local_value_does_not_live_long_enough(
469                 context,
470                 name,
471                 &scope_tree,
472                 &borrow,
473                 drop_span,
474                 borrow_spans,
475                 kind.map(|k| (k, place_span.0)),
476             ),
477             None => self.report_temporary_value_does_not_live_long_enough(
478                 context,
479                 &scope_tree,
480                 &borrow,
481                 drop_span,
482                 borrow_spans,
483                 proper_span,
484             ),
485         };
486
487         err.buffer(&mut self.errors_buffer);
488     }
489
490     fn report_local_value_does_not_live_long_enough(
491         &mut self,
492         context: Context,
493         name: &String,
494         scope_tree: &Lrc<ScopeTree>,
495         borrow: &BorrowData<'tcx>,
496         drop_span: Span,
497         borrow_spans: UseSpans,
498         kind_place: Option<(WriteKind, &Place<'tcx>)>,
499     ) -> DiagnosticBuilder<'cx> {
500         debug!(
501             "report_local_value_does_not_live_long_enough(\
502              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
503              )",
504             context, name, scope_tree, borrow, drop_span, borrow_spans
505         );
506
507         let borrow_span = borrow_spans.var_or_use();
508         let mut err = self.infcx.tcx.path_does_not_live_long_enough(
509             borrow_span,
510             &format!("`{}`", name),
511             Origin::Mir,
512         );
513
514         let explanation = self.explain_why_borrow_contains_point(context, borrow, kind_place);
515         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
516             let region_name = annotation.emit(&mut err);
517
518             err.span_label(
519                 borrow_span,
520                 format!("`{}` would have to be valid for `{}`", name, region_name)
521             );
522
523             if let Some(fn_node_id) = self.infcx.tcx.hir.as_local_node_id(self.mir_def_id) {
524                 err.span_label(
525                     drop_span,
526                     format!(
527                         "...but `{}` is only valid for the duration of the `{}` function, so it \
528                          is dropped here while still borrowed",
529                         name,
530                         self.infcx.tcx.hir.name(fn_node_id),
531                     )
532                 );
533
534                 err.note(
535                     "functions cannot return a borrow to data owned within the function's scope, \
536                      functions can only return borrows to data passed as arguments",
537                 );
538                 err.note(
539                     "to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-\
540                      references-and-borrowing.html#dangling-references>",
541                 );
542             } else {
543                 err.span_label(
544                     drop_span,
545                     format!("...but `{}` dropped here while still borrowed", name)
546                 );
547             }
548
549             if let BorrowExplanation::MustBeValidFor(..) = explanation { } else {
550                 explanation.emit(self.infcx.tcx, &mut err);
551             }
552         } else {
553             err.span_label(borrow_span, "borrowed value does not live long enough");
554             err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
555
556             borrow_spans.args_span_label(&mut err, "value captured here");
557
558             explanation.emit(self.infcx.tcx, &mut err);
559         }
560
561         err
562     }
563
564     pub(super) fn report_borrow_conflicts_with_destructor(
565         &mut self,
566         context: Context,
567         borrow: &BorrowData<'tcx>,
568         (place, drop_span): (&Place<'tcx>, Span),
569         kind: Option<WriteKind>,
570     ) {
571         debug!(
572             "report_borrow_conflicts_with_destructor(\
573              {:?}, {:?}, ({:?}, {:?}), {:?}\
574              )",
575             context, borrow, place, drop_span, kind,
576         );
577
578         let borrow_spans = self.retrieve_borrow_spans(borrow);
579         let borrow_span = borrow_spans.var_or_use();
580
581         let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
582
583         let (what_was_dropped, dropped_ty) = {
584             let desc = match self.describe_place(place) {
585                 Some(name) => format!("`{}`", name.as_str()),
586                 None => format!("temporary value"),
587             };
588             let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
589             (desc, ty)
590         };
591
592         let label = match dropped_ty.sty {
593             ty::Adt(adt, _) if adt.has_dtor(self.infcx.tcx) && !adt.is_box() => {
594                 match self.describe_place(&borrow.borrowed_place) {
595                     Some(borrowed) =>
596                         format!("here, drop of {D} needs exclusive access to `{B}`, \
597                                  because the type `{T}` implements the `Drop` trait",
598                                 D=what_was_dropped, T=dropped_ty, B=borrowed),
599                     None =>
600                         format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait",
601                                 D=what_was_dropped, T=dropped_ty),
602                 }
603             }
604             _ => format!("drop of {D} occurs here", D=what_was_dropped),
605         };
606         err.span_label(drop_span, label);
607
608         // Only give this note and suggestion if they could be relevant.
609         let explanation = self.explain_why_borrow_contains_point(
610             context, borrow, kind.map(|k| (k, place)),
611         );
612         match explanation {
613             BorrowExplanation::UsedLater {..} |
614             BorrowExplanation::UsedLaterWhenDropped {..} => {
615                 err.note("consider using a `let` binding to create a longer lived value");
616             },
617             _ => {},
618         }
619
620         explanation.emit(self.infcx.tcx, &mut err);
621
622         err.buffer(&mut self.errors_buffer);
623     }
624
625     fn report_thread_local_value_does_not_live_long_enough(
626         &mut self,
627         drop_span: Span,
628         borrow_span: Span,
629     ) -> DiagnosticBuilder<'cx> {
630         debug!(
631             "report_thread_local_value_does_not_live_long_enough(\
632              {:?}, {:?}\
633              )",
634             drop_span, borrow_span
635         );
636
637         let mut err = self.infcx.tcx.thread_local_value_does_not_live_long_enough(
638             borrow_span, Origin::Mir
639         );
640
641         err.span_label(
642             borrow_span,
643             "thread-local variables cannot be borrowed beyond the end of the function",
644         );
645         err.span_label(drop_span, "end of enclosing function is here");
646
647         err
648     }
649
650     fn report_temporary_value_does_not_live_long_enough(
651         &mut self,
652         context: Context,
653         scope_tree: &Lrc<ScopeTree>,
654         borrow: &BorrowData<'tcx>,
655         drop_span: Span,
656         borrow_spans: UseSpans,
657         proper_span: Span,
658     ) -> DiagnosticBuilder<'cx> {
659         debug!(
660             "report_temporary_value_does_not_live_long_enough(\
661              {:?}, {:?}, {:?}, {:?}, {:?}\
662              )",
663             context, scope_tree, borrow, drop_span, proper_span
664         );
665
666         let tcx = self.infcx.tcx;
667         let mut err =
668             tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
669         err.span_label(proper_span, "temporary value does not live long enough");
670         err.span_label(drop_span, "temporary value only lives until here");
671
672         let explanation = self.explain_why_borrow_contains_point(context, borrow, None);
673         match explanation {
674             BorrowExplanation::UsedLater(..) |
675             BorrowExplanation::UsedLaterInLoop(..) |
676             BorrowExplanation::UsedLaterWhenDropped(..) => {
677                 // Only give this note and suggestion if it could be relevant.
678                 err.note("consider using a `let` binding to create a longer lived value");
679             },
680             _ => {},
681         }
682         explanation.emit(self.infcx.tcx, &mut err);
683
684         borrow_spans.args_span_label(&mut err, "value captured here");
685
686         err
687     }
688
689     fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
690         let mir = self.mir;
691
692         let mut stack = Vec::new();
693         stack.extend(mir.predecessor_locations(context.loc));
694
695         let mut visited = FxHashSet();
696         let mut result = vec![];
697
698         'dfs: while let Some(l) = stack.pop() {
699             debug!(
700                 "report_use_of_moved_or_uninitialized: current_location={:?}",
701                 l
702             );
703
704             if !visited.insert(l) {
705                 continue;
706             }
707
708             // check for moves
709             let stmt_kind = mir[l.block]
710                 .statements
711                 .get(l.statement_index)
712                 .map(|s| &s.kind);
713             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
714                 // this analysis only tries to find moves explicitly
715                 // written by the user, so we ignore the move-outs
716                 // created by `StorageDead` and at the beginning
717                 // of a function.
718             } else {
719                 // If we are found a use of a.b.c which was in error, then we want to look for
720                 // moves not only of a.b.c but also a.b and a.
721                 //
722                 // Note that the moves data already includes "parent" paths, so we don't have to
723                 // worry about the other case: that is, if there is a move of a.b.c, it is already
724                 // marked as a move of a.b and a as well, so we will generate the correct errors
725                 // there.
726                 let mut mpis = vec![mpi];
727                 let move_paths = &self.move_data.move_paths;
728                 mpis.extend(move_paths[mpi].parents(move_paths));
729
730                 for moi in &self.move_data.loc_map[l] {
731                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
732                     if mpis.contains(&self.move_data.moves[*moi].path) {
733                         debug!("report_use_of_moved_or_uninitialized: found");
734                         result.push(*moi);
735
736                         // Strictly speaking, we could continue our DFS here. There may be
737                         // other moves that can reach the point of error. But it is kind of
738                         // confusing to highlight them.
739                         //
740                         // Example:
741                         //
742                         // ```
743                         // let a = vec![];
744                         // let b = a;
745                         // let c = a;
746                         // drop(a); // <-- current point of error
747                         // ```
748                         //
749                         // Because we stop the DFS here, we only highlight `let c = a`,
750                         // and not `let b = a`. We will of course also report an error at
751                         // `let c = a` which highlights `let b = a` as the move.
752                         continue 'dfs;
753                     }
754                 }
755             }
756
757             // check for inits
758             let mut any_match = false;
759             drop_flag_effects::for_location_inits(self.infcx.tcx, self.mir, self.move_data, l, |m| {
760                 if m == mpi {
761                     any_match = true;
762                 }
763             });
764             if any_match {
765                 continue 'dfs;
766             }
767
768             stack.extend(mir.predecessor_locations(l));
769         }
770
771         result
772     }
773
774     pub(super) fn report_illegal_mutation_of_borrowed(
775         &mut self,
776         context: Context,
777         (place, span): (&Place<'tcx>, Span),
778         loan: &BorrowData<'tcx>,
779     ) {
780         let loan_spans = self.retrieve_borrow_spans(loan);
781         let loan_span = loan_spans.args_or_use();
782
783         let tcx = self.infcx.tcx;
784         let mut err = tcx.cannot_assign_to_borrowed(
785             span,
786             loan_span,
787             &self.describe_place(place).unwrap_or("_".to_owned()),
788             Origin::Mir,
789         );
790
791         loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
792
793         self.explain_why_borrow_contains_point(context, loan, None).emit(self.infcx.tcx, &mut err);
794
795         err.buffer(&mut self.errors_buffer);
796     }
797
798     /// Reports an illegal reassignment; for example, an assignment to
799     /// (part of) a non-`mut` local that occurs potentially after that
800     /// local has already been initialized. `place` is the path being
801     /// assigned; `err_place` is a place providing a reason why
802     /// `place` is not mutable (e.g. the non-`mut` local `x` in an
803     /// assignment to `x.f`).
804     pub(super) fn report_illegal_reassignment(
805         &mut self,
806         _context: Context,
807         (place, span): (&Place<'tcx>, Span),
808         assigned_span: Span,
809         err_place: &Place<'tcx>,
810     ) {
811         let (from_arg, local_decl) = if let Place::Local(local) = *err_place {
812             if let LocalKind::Arg = self.mir.local_kind(local) {
813                 (true, Some(&self.mir.local_decls[local]))
814             } else {
815                 (false, Some(&self.mir.local_decls[local]))
816             }
817         } else {
818             (false, None)
819         };
820
821         // If root local is initialized immediately (everything apart from let
822         // PATTERN;) then make the error refer to that local, rather than the
823         // place being assigned later.
824         let (place_description, assigned_span) = match local_decl {
825             Some(LocalDecl {
826                 is_user_variable: Some(ClearCrossCrate::Clear),
827                 ..
828             })
829             | Some(LocalDecl {
830                 is_user_variable:
831                     Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
832                         opt_match_place: None,
833                         ..
834                     }))),
835                 ..
836             })
837             | Some(LocalDecl {
838                 is_user_variable: None,
839                 ..
840             })
841             | None => (self.describe_place(place), assigned_span),
842             Some(decl) => (self.describe_place(err_place), decl.source_info.span),
843         };
844
845         let mut err = self.infcx.tcx.cannot_reassign_immutable(
846             span,
847             place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
848             from_arg,
849             Origin::Mir,
850         );
851         let msg = if from_arg {
852             "cannot assign to immutable argument"
853         } else {
854             "cannot assign twice to immutable variable"
855         };
856         if span != assigned_span {
857             if !from_arg {
858                 let value_msg = match place_description {
859                     Some(name) => format!("`{}`", name),
860                     None => "value".to_owned(),
861                 };
862                 err.span_label(assigned_span, format!("first assignment to {}", value_msg));
863             }
864         }
865         if let Some(decl) = local_decl {
866             if let Some(name) = decl.name {
867                 if decl.can_be_made_mutable() {
868                     err.span_suggestion_with_applicability(
869                         decl.source_info.span,
870                         "make this binding mutable",
871                         format!("mut {}", name),
872                         Applicability::MachineApplicable,
873                     );
874                 }
875             }
876         }
877         err.span_label(span, msg);
878         err.buffer(&mut self.errors_buffer);
879     }
880 }
881
882 pub(super) struct IncludingDowncast(bool);
883
884 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
885     // End-user visible description of `place` if one can be found. If the
886     // place is a temporary for instance, None will be returned.
887     pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
888         self.describe_place_with_options(place, IncludingDowncast(false))
889     }
890
891     // End-user visible description of `place` if one can be found. If the
892     // place is a temporary for instance, None will be returned.
893     // `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
894     // `Downcast` and `IncludingDowncast` is true
895     pub(super) fn describe_place_with_options(
896         &self,
897         place: &Place<'tcx>,
898         including_downcast: IncludingDowncast,
899     ) -> Option<String> {
900         let mut buf = String::new();
901         match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
902             Ok(()) => Some(buf),
903             Err(()) => None,
904         }
905     }
906
907     // Appends end-user visible description of `place` to `buf`.
908     fn append_place_to_string(
909         &self,
910         place: &Place<'tcx>,
911         buf: &mut String,
912         mut autoderef: bool,
913         including_downcast: &IncludingDowncast,
914     ) -> Result<(), ()> {
915         match *place {
916             Place::Promoted(_) => {
917                 buf.push_str("promoted");
918             }
919             Place::Local(local) => {
920                 self.append_local_to_string(local, buf)?;
921             }
922             Place::Static(ref static_) => {
923                 buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
924             }
925             Place::Projection(ref proj) => {
926                 match proj.elem {
927                     ProjectionElem::Deref => {
928                         let upvar_field_projection =
929                             place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
930                         if let Some(field) = upvar_field_projection {
931                             let var_index = field.index();
932                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
933                             if self.mir.upvar_decls[var_index].by_ref {
934                                 buf.push_str(&name);
935                             } else {
936                                 buf.push_str(&format!("*{}", &name));
937                             }
938                         } else {
939                             if autoderef {
940                                 self.append_place_to_string(
941                                     &proj.base,
942                                     buf,
943                                     autoderef,
944                                     &including_downcast,
945                                 )?;
946                             } else if let Place::Local(local) = proj.base {
947                                 if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
948                                     self.mir.local_decls[local].is_user_variable
949                                 {
950                                     self.append_place_to_string(
951                                         &proj.base,
952                                         buf,
953                                         autoderef,
954                                         &including_downcast,
955                                     )?;
956                                 } else {
957                                     buf.push_str(&"*");
958                                     self.append_place_to_string(
959                                         &proj.base,
960                                         buf,
961                                         autoderef,
962                                         &including_downcast,
963                                     )?;
964                                 }
965                             } else {
966                                 buf.push_str(&"*");
967                                 self.append_place_to_string(
968                                     &proj.base,
969                                     buf,
970                                     autoderef,
971                                     &including_downcast,
972                                 )?;
973                             }
974                         }
975                     }
976                     ProjectionElem::Downcast(..) => {
977                         self.append_place_to_string(
978                             &proj.base,
979                             buf,
980                             autoderef,
981                             &including_downcast,
982                         )?;
983                         if including_downcast.0 {
984                             return Err(());
985                         }
986                     }
987                     ProjectionElem::Field(field, _ty) => {
988                         autoderef = true;
989
990                         let upvar_field_projection =
991                             place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
992                         if let Some(field) = upvar_field_projection {
993                             let var_index = field.index();
994                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
995                             buf.push_str(&name);
996                         } else {
997                             let field_name = self.describe_field(&proj.base, field);
998                             self.append_place_to_string(
999                                 &proj.base,
1000                                 buf,
1001                                 autoderef,
1002                                 &including_downcast,
1003                             )?;
1004                             buf.push_str(&format!(".{}", field_name));
1005                         }
1006                     }
1007                     ProjectionElem::Index(index) => {
1008                         autoderef = true;
1009
1010                         self.append_place_to_string(
1011                             &proj.base,
1012                             buf,
1013                             autoderef,
1014                             &including_downcast,
1015                         )?;
1016                         buf.push_str("[");
1017                         if self.append_local_to_string(index, buf).is_err() {
1018                             buf.push_str("..");
1019                         }
1020                         buf.push_str("]");
1021                     }
1022                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1023                         autoderef = true;
1024                         // Since it isn't possible to borrow an element on a particular index and
1025                         // then use another while the borrow is held, don't output indices details
1026                         // to avoid confusing the end-user
1027                         self.append_place_to_string(
1028                             &proj.base,
1029                             buf,
1030                             autoderef,
1031                             &including_downcast,
1032                         )?;
1033                         buf.push_str(&"[..]");
1034                     }
1035                 };
1036             }
1037         }
1038
1039         Ok(())
1040     }
1041
1042     // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
1043     // a name, then `Err` is returned
1044     fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
1045         let local = &self.mir.local_decls[local_index];
1046         match local.name {
1047             Some(name) => {
1048                 buf.push_str(&name.to_string());
1049                 Ok(())
1050             }
1051             None => Err(()),
1052         }
1053     }
1054
1055     // End-user visible description of the `field`nth field of `base`
1056     fn describe_field(&self, base: &Place, field: Field) -> String {
1057         match *base {
1058             Place::Local(local) => {
1059                 let local = &self.mir.local_decls[local];
1060                 self.describe_field_from_ty(&local.ty, field)
1061             }
1062             Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field),
1063             Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
1064             Place::Projection(ref proj) => match proj.elem {
1065                 ProjectionElem::Deref => self.describe_field(&proj.base, field),
1066                 ProjectionElem::Downcast(def, variant_index) => format!(
1067                     "{}",
1068                     def.variants[variant_index].fields[field.index()].ident
1069                 ),
1070                 ProjectionElem::Field(_, field_type) => {
1071                     self.describe_field_from_ty(&field_type, field)
1072                 }
1073                 ProjectionElem::Index(..)
1074                 | ProjectionElem::ConstantIndex { .. }
1075                 | ProjectionElem::Subslice { .. } => {
1076                     self.describe_field(&proj.base, field).to_string()
1077                 }
1078             },
1079         }
1080     }
1081
1082     // End-user visible description of the `field_index`nth field of `ty`
1083     fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
1084         if ty.is_box() {
1085             // If the type is a box, the field is described from the boxed type
1086             self.describe_field_from_ty(&ty.boxed_ty(), field)
1087         } else {
1088             match ty.sty {
1089                 ty::Adt(def, _) => if def.is_enum() {
1090                     field.index().to_string()
1091                 } else {
1092                     def.non_enum_variant().fields[field.index()]
1093                         .ident
1094                         .to_string()
1095                 },
1096                 ty::Tuple(_) => field.index().to_string(),
1097                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
1098                     self.describe_field_from_ty(&ty, field)
1099                 }
1100                 ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field),
1101                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
1102                     // Convert the def-id into a node-id. node-ids are only valid for
1103                     // the local code in the current crate, so this returns an `Option` in case
1104                     // the closure comes from another crate. But in that case we wouldn't
1105                     // be borrowck'ing it, so we can just unwrap:
1106                     let node_id = self.infcx.tcx.hir.as_local_node_id(def_id).unwrap();
1107                     let freevar = self.infcx.tcx.with_freevars(node_id, |fv| fv[field.index()]);
1108
1109                     self.infcx.tcx.hir.name(freevar.var_id()).to_string()
1110                 }
1111                 _ => {
1112                     // Might need a revision when the fields in trait RFC is implemented
1113                     // (https://github.com/rust-lang/rfcs/pull/1546)
1114                     bug!(
1115                         "End-user description not implemented for field access on `{:?}`",
1116                         ty.sty
1117                     );
1118                 }
1119             }
1120         }
1121     }
1122
1123     // Retrieve type of a place for the current MIR representation
1124     fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option<ty::Ty> {
1125         match place {
1126             Place::Local(local) => {
1127                 let local = &self.mir.local_decls[*local];
1128                 Some(local.ty)
1129             }
1130             Place::Promoted(ref prom) => Some(prom.1),
1131             Place::Static(ref st) => Some(st.ty),
1132             Place::Projection(ref proj) => match proj.elem {
1133                 ProjectionElem::Field(_, ty) => Some(ty),
1134                 _ => None,
1135             },
1136         }
1137     }
1138
1139     /// Check if a place is a thread-local static.
1140     pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
1141         if let Place::Static(statik) = place {
1142             let attrs = self.infcx.tcx.get_attrs(statik.def_id);
1143             let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
1144
1145             debug!(
1146                 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
1147                 attrs, is_thread_local
1148             );
1149             is_thread_local
1150         } else {
1151             debug!("is_place_thread_local: no");
1152             false
1153         }
1154     }
1155
1156     /// Returns the `FakeReadCause` at this location if it is a `FakeRead` statement.
1157     pub(super) fn retrieve_fake_read_cause_for_location(
1158         &self,
1159         location: &Location,
1160     ) -> Option<FakeReadCause> {
1161         let stmt = self.mir.basic_blocks()[location.block]
1162             .statements
1163             .get(location.statement_index)?;
1164         if let StatementKind::FakeRead(cause, _) = stmt.kind {
1165             Some(cause)
1166         } else {
1167             None
1168         }
1169     }
1170
1171     /// Annotate argument and return type of function and closure with (synthesized) lifetime for
1172     /// borrow of local value that does not live long enough.
1173     fn annotate_argument_and_return_for_borrow(
1174         &self,
1175         borrow: &BorrowData<'tcx>,
1176     ) -> Option<AnnotatedBorrowFnSignature> {
1177         // There are two cases that need handled: when a closure is involved and
1178         // when a closure is not involved.
1179         let location = borrow.reserve_location;
1180         let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
1181
1182         match self.mir[location.block].statements.get(location.statement_index) {
1183             // When a closure is involved, we expect the reserve location to be an assignment
1184             // to a temporary local, which will be followed by a closure.
1185             Some(&Statement {
1186                 kind: StatementKind::Assign(Place::Local(local), _),
1187                 ..
1188             }) if self.mir.local_kind(local) == LocalKind::Temp => {
1189                 // Look for the statements within this block after assigning to a local to see
1190                 // if we have a closure. If we do, then annotate it.
1191                 for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1192                     if let StatementKind::Assign(
1193                         _,
1194                         Rvalue::Aggregate(
1195                             box AggregateKind::Closure(def_id, substs),
1196                             _
1197                         )
1198                     ) = stmt.kind {
1199                         return self.annotate_fn_sig(
1200                             def_id,
1201                             self.infcx.closure_sig(def_id, substs)
1202                         );
1203                     }
1204                 }
1205             }
1206             _ => {}
1207         }
1208
1209         // If this is not the case, then return if we're currently on a closure (as we
1210         // don't have a substs to get the PolyFnSig) or attempt to get the arguments
1211         // and return type of the function.
1212         if is_closure {
1213             None
1214         } else {
1215             let ty = self.infcx.tcx.type_of(self.mir_def_id);
1216             match ty.sty {
1217                 ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) =>
1218                     self.annotate_fn_sig(
1219                         self.mir_def_id,
1220                         self.infcx.tcx.fn_sig(self.mir_def_id)
1221                     ),
1222                 _ => None,
1223             }
1224         }
1225     }
1226
1227     /// Annotate the first argument and return type of a function signature if they are
1228     /// references.
1229     fn annotate_fn_sig(
1230         &self,
1231         did: DefId,
1232         sig: ty::PolyFnSig<'tcx>,
1233     ) -> Option<AnnotatedBorrowFnSignature> {
1234         let is_closure = self.infcx.tcx.is_closure(did);
1235         let fn_node_id = self.infcx.tcx.hir.as_local_node_id(did)?;
1236         let fn_decl = self.infcx.tcx.hir.fn_decl(fn_node_id)?;
1237
1238         // If there is one argument and this error is being reported, that means
1239         // that the lifetime of the borrow could not be made to match the single
1240         // argument's lifetime. We can highlight it.
1241         //
1242         // If there is more than one argument and this error is being reported, that
1243         // means there must be a self parameter - as otherwise there would be an error
1244         // from lifetime elision and not this. So we highlight the self parameter.
1245         let argument_span = fn_decl.inputs.first()?.span;
1246         let argument_ty = sig.inputs().skip_binder().first()?;
1247         if is_closure {
1248             // Closure arguments are wrapped in a tuple, so we need to get the first
1249             // from that.
1250             let argument_ty = if let ty::TyKind::Tuple(elems) = argument_ty.sty {
1251                 let argument_ty = elems.first()?;
1252                 if let ty::TyKind::Ref(_, _, _) = argument_ty.sty {
1253                     argument_ty
1254                 } else {
1255                     return None;
1256                 }
1257             } else {
1258                 return None
1259             };
1260
1261             Some(AnnotatedBorrowFnSignature::Closure {
1262                 argument_ty,
1263                 argument_span,
1264             })
1265         } else if let ty::TyKind::Ref(argument_region, _, _) = argument_ty.sty {
1266             // We only consider the return type for functions.
1267             let return_span = fn_decl.output.span();
1268
1269             let return_ty = sig.output();
1270             let (return_region, return_ty) = if let ty::TyKind::Ref(
1271                 return_region, _, _
1272             ) = return_ty.skip_binder().sty {
1273                 (return_region, *return_ty.skip_binder())
1274             } else {
1275                 return None;
1276             };
1277
1278             Some(AnnotatedBorrowFnSignature::Function {
1279                 argument_ty,
1280                 argument_span,
1281                 return_ty,
1282                 return_span,
1283                 regions_equal: return_region == argument_region,
1284             })
1285         } else {
1286             None
1287         }
1288     }
1289 }
1290
1291 #[derive(Debug)]
1292 enum AnnotatedBorrowFnSignature<'tcx> {
1293     Function {
1294         argument_ty: ty::Ty<'tcx>,
1295         argument_span: Span,
1296         return_ty: ty::Ty<'tcx>,
1297         return_span: Span,
1298         regions_equal: bool,
1299     },
1300     Closure {
1301         argument_ty: ty::Ty<'tcx>,
1302         argument_span: Span,
1303     }
1304 }
1305
1306 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
1307     fn emit(
1308         &self,
1309         diag: &mut DiagnosticBuilder<'_>
1310     ) -> String {
1311         let (argument_ty, argument_span) = match self {
1312             AnnotatedBorrowFnSignature::Function {
1313                 argument_ty,
1314                 argument_span,
1315                 ..
1316             } => (argument_ty, argument_span),
1317             AnnotatedBorrowFnSignature::Closure {
1318                 argument_ty,
1319                 argument_span,
1320             } => (argument_ty, argument_span),
1321         };
1322
1323         let (argument_region_name, argument_ty_name) = (
1324             self.get_region_name_for_ty(argument_ty, 0),
1325             self.get_name_for_ty(argument_ty, 0),
1326         );
1327         diag.span_label(
1328             *argument_span,
1329             format!("has type `{}`", argument_ty_name)
1330         );
1331
1332         // Only emit labels for the return value when we're annotating a function.
1333         if let AnnotatedBorrowFnSignature::Function {
1334             return_ty,
1335             return_span,
1336             regions_equal,
1337             ..
1338         } = self {
1339             let counter = if *regions_equal { 0 } else { 1 };
1340             let (return_region_name, return_ty_name) = (
1341                 self.get_region_name_for_ty(return_ty, counter),
1342                 self.get_name_for_ty(return_ty, counter)
1343             );
1344
1345             let types_equal = return_ty_name == argument_ty_name;
1346             diag.span_label(
1347                 *return_span,
1348                 format!(
1349                     "{}has type `{}`",
1350                     if types_equal { "also " } else { "" },
1351                     return_ty_name,
1352                 )
1353             );
1354
1355             return_region_name
1356         } else {
1357             argument_region_name
1358         }
1359     }
1360
1361     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
1362     /// name where required.
1363     fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
1364         // We need to add synthesized lifetimes where appropriate. We do
1365         // this by hooking into the pretty printer and telling it to label the
1366         // lifetimes without names with the value `'0`.
1367         match ty.sty {
1368             ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) |
1369             ty::TyKind::Ref(ty::RegionKind::ReSkolemized(_, br), _, _) =>
1370                 with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty)),
1371             _ => format!("{}", ty),
1372         }
1373     }
1374
1375     /// Return the name of the provided `Ty` (that must be a reference)'s region with a
1376     /// synthesized lifetime name where required.
1377     fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
1378         match ty.sty {
1379             ty::TyKind::Ref(region, _, _) => match region {
1380                 ty::RegionKind::ReLateBound(_, br) |
1381                 ty::RegionKind::ReSkolemized(_, br) =>
1382                     with_highlight_region_for_bound_region(*br, counter, || format!("{}", region)),
1383                 _ => format!("{}", region),
1384             }
1385             _ => bug!("ty for annotation of borrow region is not a reference"),
1386         }
1387     }
1388 }
1389
1390 // The span(s) associated to a use of a place.
1391 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1392 pub(super) enum UseSpans {
1393     // The access is caused by capturing a variable for a closure.
1394     ClosureUse {
1395         // The span of the args of the closure, including the `move` keyword if
1396         // it's present.
1397         args_span: Span,
1398         // The span of the first use of the captured variable inside the closure.
1399         var_span: Span,
1400     },
1401     // This access has a single span associated to it: common case.
1402     OtherUse(Span),
1403 }
1404
1405 impl UseSpans {
1406     pub(super) fn args_or_use(self) -> Span {
1407         match self {
1408             UseSpans::ClosureUse {
1409                 args_span: span, ..
1410             }
1411             | UseSpans::OtherUse(span) => span,
1412         }
1413     }
1414
1415     pub(super) fn var_or_use(self) -> Span {
1416         match self {
1417             UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
1418         }
1419     }
1420
1421     // Add a span label to the arguments of the closure, if it exists.
1422     pub(super) fn args_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
1423         if let UseSpans::ClosureUse { args_span, .. } = self {
1424             err.span_label(args_span, message);
1425         }
1426     }
1427
1428     // Add a span label to the use of the captured variable, if it exists.
1429     pub(super) fn var_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
1430         if let UseSpans::ClosureUse { var_span, .. } = self {
1431             err.span_label(var_span, message);
1432         }
1433     }
1434
1435     pub(super) fn for_closure(self) -> bool {
1436         match self {
1437             UseSpans::ClosureUse { .. } => true,
1438             UseSpans::OtherUse(_) => false,
1439         }
1440     }
1441
1442     pub(super) fn or_else<F>(self, if_other: F) -> Self
1443     where
1444         F: FnOnce() -> Self,
1445     {
1446         match self {
1447             closure @ UseSpans::ClosureUse { .. } => closure,
1448             UseSpans::OtherUse(_) => if_other(),
1449         }
1450     }
1451 }
1452
1453 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1454     /// Finds the spans associated to a move or copy of move_place at location.
1455     pub(super) fn move_spans(
1456         &self,
1457         moved_place: &Place<'tcx>, // Could also be an upvar.
1458         location: Location,
1459     ) -> UseSpans {
1460         use self::UseSpans::*;
1461         use rustc::hir::ExprKind::Closure;
1462         use rustc::mir::AggregateKind;
1463
1464         let stmt = match self.mir[location.block]
1465             .statements
1466             .get(location.statement_index)
1467         {
1468             Some(stmt) => stmt,
1469             None => return OtherUse(self.mir.source_info(location).span),
1470         };
1471
1472         if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
1473             if let AggregateKind::Closure(def_id, _) = **kind {
1474                 debug!("find_closure_move_span: found closure {:?}", places);
1475
1476                 if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
1477                     if let Closure(
1478                         _, _, _, args_span, _
1479                     ) = self.infcx.tcx.hir.expect_expr(node_id).node {
1480                         if let Some(var_span) = self.infcx.tcx.with_freevars(node_id, |freevars| {
1481                             for (v, place) in freevars.iter().zip(places) {
1482                                 match place {
1483                                     Operand::Copy(place) | Operand::Move(place)
1484                                         if moved_place == place =>
1485                                     {
1486                                         debug!(
1487                                             "find_closure_move_span: found captured local {:?}",
1488                                             place
1489                                         );
1490                                         return Some(v.span);
1491                                     }
1492                                     _ => {}
1493                                 }
1494                             }
1495                             None
1496                         }) {
1497                             return ClosureUse {
1498                                 args_span,
1499                                 var_span,
1500                             };
1501                         }
1502                     }
1503                 }
1504             }
1505         }
1506
1507         return OtherUse(stmt.source_info.span);
1508     }
1509
1510     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
1511     /// and its usage of the local assigned at `location`.
1512     /// This is done by searching in statements succeeding `location`
1513     /// and originating from `maybe_closure_span`.
1514     pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
1515         use self::UseSpans::*;
1516         use rustc::hir::ExprKind::Closure;
1517
1518         let local = match self.mir[location.block]
1519             .statements
1520             .get(location.statement_index)
1521         {
1522             Some(&Statement {
1523                 kind: StatementKind::Assign(Place::Local(local), _),
1524                 ..
1525             }) => local,
1526             _ => return OtherUse(use_span),
1527         };
1528
1529         if self.mir.local_kind(local) != LocalKind::Temp {
1530             // operands are always temporaries.
1531             return OtherUse(use_span);
1532         }
1533
1534         for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1535             if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
1536                 if let AggregateKind::Closure(def_id, _) = **kind {
1537                     debug!("find_closure_borrow_span: found closure {:?}", places);
1538
1539                     return if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
1540                         let args_span = if let Closure(_, _, _, span, _) =
1541                             self.infcx.tcx.hir.expect_expr(node_id).node
1542                         {
1543                             span
1544                         } else {
1545                             return OtherUse(use_span);
1546                         };
1547
1548                         self.infcx.tcx
1549                             .with_freevars(node_id, |freevars| {
1550                                 for (v, place) in freevars.iter().zip(places) {
1551                                     match *place {
1552                                         Operand::Copy(Place::Local(l))
1553                                         | Operand::Move(Place::Local(l))
1554                                             if local == l =>
1555                                         {
1556                                             debug!(
1557                                                 "find_closure_borrow_span: found captured local \
1558                                                  {:?}",
1559                                                 l
1560                                             );
1561                                             return Some(v.span);
1562                                         }
1563                                         _ => {}
1564                                     }
1565                                 }
1566                                 None
1567                             }).map(|var_span| ClosureUse {
1568                                 args_span,
1569                                 var_span,
1570                             }).unwrap_or(OtherUse(use_span))
1571                     } else {
1572                         OtherUse(use_span)
1573                     };
1574                 }
1575             }
1576
1577             if use_span != stmt.source_info.span {
1578                 break;
1579             }
1580         }
1581
1582         OtherUse(use_span)
1583     }
1584
1585     /// Helper to retrieve span(s) of given borrow from the current MIR
1586     /// representation
1587     pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData) -> UseSpans {
1588         let span = self.mir.source_info(borrow.reserve_location).span;
1589         self.borrow_spans(span, borrow.reserve_location)
1590     }
1591 }