]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/error_reporting.rs
Rollup merge of #54964 - tromey:run-both-gdb-and-lldb-tests, r=nikomatsakis
[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::nll::explain_borrow::BorrowExplanation;
12 use borrow_check::prefixes::IsPrefixOf;
13 use borrow_check::WriteKind;
14 use rustc::hir;
15 use rustc::hir::def_id::DefId;
16 use rustc::middle::region::ScopeTree;
17 use rustc::mir::{
18     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Field, Local,
19     LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem,
20     Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
21 };
22 use rustc::ty;
23 use rustc::util::ppaux::with_highlight_region_for_bound_region;
24 use rustc_data_structures::fx::FxHashSet;
25 use rustc_data_structures::sync::Lrc;
26 use rustc_errors::{Applicability, DiagnosticBuilder};
27 use syntax_pos::Span;
28
29 use super::borrow_set::BorrowData;
30 use super::{Context, MirBorrowckCtxt};
31 use super::{InitializationRequiringAction, PrefixSet};
32
33 use dataflow::drop_flag_effects;
34 use dataflow::move_paths::indexes::MoveOutIndex;
35 use dataflow::move_paths::MovePathIndex;
36 use util::borrowck_errors::{BorrowckErrors, Origin};
37
38 #[derive(Debug)]
39 struct MoveSite {
40     /// Index of the "move out" that we found. The `MoveData` can
41     /// then tell us where the move occurred.
42     moi: MoveOutIndex,
43
44     /// True if we traversed a back edge while walking from the point
45     /// of error to the move site.
46     traversed_back_edge: bool
47 }
48
49 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
50     pub(super) fn report_use_of_moved_or_uninitialized(
51         &mut self,
52         context: Context,
53         desired_action: InitializationRequiringAction,
54         (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
55         mpi: MovePathIndex,
56     ) {
57         debug!(
58             "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} \
59              moved_place={:?} used_place={:?} span={:?} mpi={:?}",
60             context, desired_action, moved_place, used_place, span, mpi
61         );
62
63         let use_spans = self.move_spans(moved_place, context.loc)
64             .or_else(|| self.borrow_spans(span, context.loc));
65         let span = use_spans.args_or_use();
66
67         let move_site_vec = self.get_moved_indexes(context, mpi);
68         debug!(
69             "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
70             move_site_vec
71         );
72         let move_out_indices: Vec<_> = move_site_vec
73             .iter()
74             .map(|move_site| move_site.moi)
75             .collect();
76
77         if move_out_indices.is_empty() {
78             let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
79
80             if self.uninitialized_error_reported
81                 .contains(&root_place.clone())
82             {
83                 debug!(
84                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
85                     root_place
86                 );
87                 return;
88             }
89
90             self.uninitialized_error_reported.insert(root_place.clone());
91
92             let item_msg = match self.describe_place_with_options(used_place,
93                                                                   IncludingDowncast(true)) {
94                 Some(name) => format!("`{}`", name),
95                 None => "value".to_owned(),
96             };
97             let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
98                 span,
99                 desired_action.as_noun(),
100                 &self.describe_place_with_options(moved_place, IncludingDowncast(true))
101                     .unwrap_or("_".to_owned()),
102                 Origin::Mir,
103             );
104             err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
105
106             use_spans.var_span_label(
107                 &mut err,
108                 format!("{} occurs due to use in closure", desired_action.as_noun()),
109             );
110
111             err.buffer(&mut self.errors_buffer);
112         } else {
113             if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
114                 if self.prefixes(&reported_place, PrefixSet::All)
115                     .any(|p| p == used_place)
116                 {
117                     debug!(
118                         "report_use_of_moved_or_uninitialized place: error suppressed \
119                          mois={:?}",
120                         move_out_indices
121                     );
122                     return;
123                 }
124             }
125
126             let msg = ""; //FIXME: add "partially " or "collaterally "
127
128             let mut err = self.infcx.tcx.cannot_act_on_moved_value(
129                 span,
130                 desired_action.as_noun(),
131                 msg,
132                 self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
133                 Origin::Mir,
134             );
135
136             let mut is_loop_move = false;
137             for move_site in &move_site_vec {
138                 let move_out = self.move_data.moves[(*move_site).moi];
139                 let moved_place = &self.move_data.move_paths[move_out.path].place;
140
141                 let move_spans = self.move_spans(moved_place, move_out.source);
142                 let move_span = move_spans.args_or_use();
143
144                 let move_msg = if move_spans.for_closure() {
145                     " into closure"
146                 } else {
147                     ""
148                 };
149
150                 if span == move_span {
151                     err.span_label(
152                         span,
153                         format!("value moved{} here, in previous iteration of loop", move_msg),
154                     );
155                     is_loop_move = true;
156                 } else if move_site.traversed_back_edge {
157                     err.span_label(
158                         move_span,
159                         format!(
160                             "value moved{} here, in previous iteration of loop",
161                             move_msg
162                         ),
163                     );
164                 } else {
165                     err.span_label(move_span, format!("value moved{} here", move_msg));
166                     move_spans.var_span_label(&mut err, "variable moved due to use in closure");
167                 };
168             }
169
170             use_spans.var_span_label(
171                 &mut err,
172                 format!("{} occurs due to use in closure", desired_action.as_noun()),
173             );
174
175             if !is_loop_move {
176                 err.span_label(
177                     span,
178                     format!(
179                         "value {} here after move",
180                         desired_action.as_verb_in_past_tense()
181                     ),
182                 );
183             }
184
185             if let Some(ty) = self.retrieve_type_for_place(used_place) {
186                 let needs_note = match ty.sty {
187                     ty::Closure(id, _) => {
188                         let tables = self.infcx.tcx.typeck_tables_of(id);
189                         let node_id = self.infcx.tcx.hir.as_local_node_id(id).unwrap();
190                         let hir_id = self.infcx.tcx.hir.node_to_hir_id(node_id);
191                         if tables.closure_kind_origins().get(hir_id).is_some() {
192                             false
193                         } else {
194                             true
195                         }
196                     }
197                     _ => true,
198                 };
199
200                 if needs_note {
201                     let mpi = self.move_data.moves[move_out_indices[0]].path;
202                     let place = &self.move_data.move_paths[mpi].place;
203
204                     if let Some(ty) = self.retrieve_type_for_place(place) {
205                         let note_msg = match self.describe_place_with_options(
206                             place,
207                             IncludingDowncast(true),
208                         ) {
209                             Some(name) => format!("`{}`", name),
210                             None => "value".to_owned(),
211                         };
212
213                         err.note(&format!(
214                             "move occurs because {} has type `{}`, \
215                              which does not implement the `Copy` trait",
216                             note_msg, ty
217                         ));
218                     }
219                 }
220             }
221
222             if let Some((_, mut old_err)) = self.move_error_reported
223                 .insert(move_out_indices, (used_place.clone(), err))
224             {
225                 // Cancel the old error so it doesn't ICE.
226                 old_err.cancel();
227             }
228         }
229     }
230
231     pub(super) fn report_move_out_while_borrowed(
232         &mut self,
233         context: Context,
234         (place, _span): (&Place<'tcx>, Span),
235         borrow: &BorrowData<'tcx>,
236     ) {
237         let tcx = self.infcx.tcx;
238         let value_msg = match self.describe_place(place) {
239             Some(name) => format!("`{}`", name),
240             None => "value".to_owned(),
241         };
242         let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
243             Some(name) => format!("`{}`", name),
244             None => "value".to_owned(),
245         };
246
247         let borrow_spans = self.retrieve_borrow_spans(borrow);
248         let borrow_span = borrow_spans.args_or_use();
249
250         let move_spans = self.move_spans(place, context.loc);
251         let span = move_spans.args_or_use();
252
253         let mut err = tcx.cannot_move_when_borrowed(
254             span,
255             &self.describe_place(place).unwrap_or("_".to_owned()),
256             Origin::Mir,
257         );
258         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
259         err.span_label(span, format!("move out of {} occurs here", value_msg));
260
261         borrow_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
262
263         move_spans.var_span_label(&mut err, "move occurs due to use in closure");
264
265         self.explain_why_borrow_contains_point(context, borrow, None)
266             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
267         err.buffer(&mut self.errors_buffer);
268     }
269
270     pub(super) fn report_use_while_mutably_borrowed(
271         &mut self,
272         context: Context,
273         (place, _span): (&Place<'tcx>, Span),
274         borrow: &BorrowData<'tcx>,
275     ) {
276         let tcx = self.infcx.tcx;
277
278         let borrow_spans = self.retrieve_borrow_spans(borrow);
279         let borrow_span = borrow_spans.args_or_use();
280
281         // Conflicting borrows are reported separately, so only check for move
282         // captures.
283         let use_spans = self.move_spans(place, context.loc);
284         let span = use_spans.var_or_use();
285
286         let mut err = tcx.cannot_use_when_mutably_borrowed(
287             span,
288             &self.describe_place(place).unwrap_or("_".to_owned()),
289             borrow_span,
290             &self.describe_place(&borrow.borrowed_place)
291                 .unwrap_or("_".to_owned()),
292             Origin::Mir,
293         );
294
295         borrow_spans.var_span_label(&mut err, {
296             let place = &borrow.borrowed_place;
297             let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
298
299             format!("borrow occurs due to use of `{}` in closure", desc_place)
300         });
301
302         self.explain_why_borrow_contains_point(context, borrow, None)
303             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
304         err.buffer(&mut self.errors_buffer);
305     }
306
307     pub(super) fn report_conflicting_borrow(
308         &mut self,
309         context: Context,
310         (place, span): (&Place<'tcx>, Span),
311         gen_borrow_kind: BorrowKind,
312         issued_borrow: &BorrowData<'tcx>,
313     ) {
314         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
315         let issued_span = issued_spans.args_or_use();
316
317         let borrow_spans = self.borrow_spans(span, context.loc);
318         let span = borrow_spans.args_or_use();
319
320         let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
321         let tcx = self.infcx.tcx;
322
323         let first_borrow_desc;
324
325         // FIXME: supply non-"" `opt_via` when appropriate
326         let mut err = match (
327             gen_borrow_kind,
328             "immutable",
329             "mutable",
330             issued_borrow.kind,
331             "immutable",
332             "mutable",
333         ) {
334             (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
335                 first_borrow_desc = "mutable ";
336                 tcx.cannot_reborrow_already_borrowed(
337                     span,
338                     &desc_place,
339                     "",
340                     lft,
341                     issued_span,
342                     "it",
343                     rgt,
344                     "",
345                     None,
346                     Origin::Mir,
347                 )
348             }
349             (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
350                 first_borrow_desc = "immutable ";
351                 tcx.cannot_reborrow_already_borrowed(
352                     span,
353                     &desc_place,
354                     "",
355                     lft,
356                     issued_span,
357                     "it",
358                     rgt,
359                     "",
360                     None,
361                     Origin::Mir,
362                 )
363             }
364
365             (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
366                 first_borrow_desc = "first ";
367                 tcx.cannot_mutably_borrow_multiply(
368                     span,
369                     &desc_place,
370                     "",
371                     issued_span,
372                     "",
373                     None,
374                     Origin::Mir,
375                 )
376             }
377
378             (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
379                 first_borrow_desc = "first ";
380                 tcx.cannot_uniquely_borrow_by_two_closures(
381                     span,
382                     &desc_place,
383                     issued_span,
384                     None,
385                     Origin::Mir,
386                 )
387             }
388
389             (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
390             | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
391                 let mut err = tcx.cannot_mutate_in_match_guard(
392                     span,
393                     issued_span,
394                     &desc_place,
395                     "mutably borrow",
396                     Origin::Mir,
397                 );
398                 borrow_spans.var_span_label(
399                     &mut err,
400                     format!("borrow occurs due to use of `{}` in closure", desc_place),
401                 );
402                 err.buffer(&mut self.errors_buffer);
403
404                 return;
405             }
406
407             (BorrowKind::Unique, _, _, _, _, _) => {
408                 first_borrow_desc = "first ";
409                 tcx.cannot_uniquely_borrow_by_one_closure(
410                     span,
411                     &desc_place,
412                     "",
413                     issued_span,
414                     "it",
415                     "",
416                     None,
417                     Origin::Mir,
418                 )
419             },
420
421             (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
422                 first_borrow_desc = "first ";
423                 tcx.cannot_reborrow_already_uniquely_borrowed(
424                     span,
425                     &desc_place,
426                     "",
427                     lft,
428                     issued_span,
429                     "",
430                     None,
431                     Origin::Mir,
432                 )
433             }
434
435             (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
436                 first_borrow_desc = "first ";
437                 tcx.cannot_reborrow_already_uniquely_borrowed(
438                     span,
439                     &desc_place,
440                     "",
441                     lft,
442                     issued_span,
443                     "",
444                     None,
445                     Origin::Mir,
446                 )
447             }
448
449             (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
450             | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
451                 // Shallow borrows are uses from the user's point of view.
452                 self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
453                 return;
454             }
455             (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
456             | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
457             | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
458             | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
459         };
460
461         if issued_spans == borrow_spans {
462             borrow_spans.var_span_label(
463                 &mut err,
464                 format!("borrows occur due to use of `{}` in closure", desc_place),
465             );
466         } else {
467             let borrow_place = &issued_borrow.borrowed_place;
468             let borrow_place_desc = self.describe_place(borrow_place).unwrap_or("_".to_owned());
469             issued_spans.var_span_label(
470                 &mut err,
471                 format!(
472                     "first borrow occurs due to use of `{}` in closure",
473                     borrow_place_desc
474                 ),
475             );
476
477             borrow_spans.var_span_label(
478                 &mut err,
479                 format!(
480                     "second borrow occurs due to use of `{}` in closure",
481                     desc_place
482                 ),
483             );
484         }
485
486         self.explain_why_borrow_contains_point(context, issued_borrow, None)
487             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, first_borrow_desc);
488
489         err.buffer(&mut self.errors_buffer);
490     }
491
492     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
493     ///
494     /// This means that some data referenced by `borrow` needs to live
495     /// past the point where the StorageDeadOrDrop of `place` occurs.
496     /// This is usually interpreted as meaning that `place` has too
497     /// short a lifetime. (But sometimes it is more useful to report
498     /// it as a more direct conflict between the execution of a
499     /// `Drop::drop` with an aliasing borrow.)
500     pub(super) fn report_borrowed_value_does_not_live_long_enough(
501         &mut self,
502         context: Context,
503         borrow: &BorrowData<'tcx>,
504         place_span: (&Place<'tcx>, Span),
505         kind: Option<WriteKind>,
506     ) {
507         debug!(
508             "report_borrowed_value_does_not_live_long_enough(\
509              {:?}, {:?}, {:?}, {:?}\
510              )",
511             context, borrow, place_span, kind
512         );
513
514         let drop_span = place_span.1;
515         let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id);
516         let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
517             .last()
518             .unwrap();
519
520         let borrow_spans = self.retrieve_borrow_spans(borrow);
521         let borrow_span = borrow_spans.var_or_use();
522
523         let proper_span = match *root_place {
524             Place::Local(local) => self.mir.local_decls[local].source_info.span,
525             _ => drop_span,
526         };
527
528         if self.access_place_error_reported
529             .contains(&(root_place.clone(), borrow_span))
530         {
531             debug!(
532                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
533                 borrow_span
534             );
535             return;
536         }
537
538         self.access_place_error_reported
539             .insert((root_place.clone(), borrow_span));
540
541         if let StorageDeadOrDrop::Destructor(dropped_ty) =
542             self.classify_drop_access_kind(&borrow.borrowed_place)
543         {
544             // If a borrow of path `B` conflicts with drop of `D` (and
545             // we're not in the uninteresting case where `B` is a
546             // prefix of `D`), then report this as a more interesting
547             // destructor conflict.
548             if !borrow.borrowed_place.is_prefix_of(place_span.0) {
549                 self.report_borrow_conflicts_with_destructor(
550                     context, borrow, place_span, kind, dropped_ty,
551                 );
552                 return;
553             }
554         }
555
556         let err = match &self.describe_place(&borrow.borrowed_place) {
557             Some(_) if self.is_place_thread_local(root_place) => {
558                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
559             }
560             Some(name) => self.report_local_value_does_not_live_long_enough(
561                 context,
562                 name,
563                 &scope_tree,
564                 &borrow,
565                 drop_span,
566                 borrow_spans,
567                 kind.map(|k| (k, place_span.0)),
568             ),
569             None => self.report_temporary_value_does_not_live_long_enough(
570                 context,
571                 &scope_tree,
572                 &borrow,
573                 drop_span,
574                 borrow_spans,
575                 proper_span,
576             ),
577         };
578
579         err.buffer(&mut self.errors_buffer);
580     }
581
582     fn report_local_value_does_not_live_long_enough(
583         &mut self,
584         context: Context,
585         name: &String,
586         scope_tree: &Lrc<ScopeTree>,
587         borrow: &BorrowData<'tcx>,
588         drop_span: Span,
589         borrow_spans: UseSpans,
590         kind_place: Option<(WriteKind, &Place<'tcx>)>,
591     ) -> DiagnosticBuilder<'cx> {
592         debug!(
593             "report_local_value_does_not_live_long_enough(\
594              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
595              )",
596             context, name, scope_tree, borrow, drop_span, borrow_spans
597         );
598
599         let borrow_span = borrow_spans.var_or_use();
600         let mut err = self.infcx.tcx.path_does_not_live_long_enough(
601             borrow_span,
602             &format!("`{}`", name),
603             Origin::Mir,
604         );
605
606         let explanation = self.explain_why_borrow_contains_point(context, borrow, kind_place);
607         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
608             let region_name = annotation.emit(&mut err);
609
610             err.span_label(
611                 borrow_span,
612                 format!("`{}` would have to be valid for `{}`...", name, region_name),
613             );
614
615             if let Some(fn_node_id) = self.infcx.tcx.hir.as_local_node_id(self.mir_def_id) {
616                 err.span_label(
617                     drop_span,
618                     format!(
619                         "...but `{}` will be dropped here, when the function `{}` returns",
620                         name,
621                         self.infcx.tcx.hir.name(fn_node_id),
622                     ),
623                 );
624
625                 err.note(
626                     "functions cannot return a borrow to data owned within the function's scope, \
627                      functions can only return borrows to data passed as arguments",
628                 );
629                 err.note(
630                     "to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch04-02-\
631                      references-and-borrowing.html#dangling-references>",
632                 );
633             } else {
634                 err.span_label(
635                     drop_span,
636                     format!("...but `{}` dropped here while still borrowed", name),
637                 );
638             }
639
640             if let BorrowExplanation::MustBeValidFor(..) = explanation {
641             } else {
642                 explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
643             }
644         } else {
645             err.span_label(borrow_span, "borrowed value does not live long enough");
646             err.span_label(
647                 drop_span,
648                 format!("`{}` dropped here while still borrowed", name),
649             );
650
651             borrow_spans.args_span_label(&mut err, "value captured here");
652
653             explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
654         }
655
656         err
657     }
658
659     pub(super) fn report_borrow_conflicts_with_destructor(
660         &mut self,
661         context: Context,
662         borrow: &BorrowData<'tcx>,
663         (place, drop_span): (&Place<'tcx>, Span),
664         kind: Option<WriteKind>,
665         dropped_ty: ty::Ty<'tcx>,
666     ) {
667         debug!(
668             "report_borrow_conflicts_with_destructor(\
669              {:?}, {:?}, ({:?}, {:?}), {:?}\
670              )",
671             context, borrow, place, drop_span, kind,
672         );
673
674         let borrow_spans = self.retrieve_borrow_spans(borrow);
675         let borrow_span = borrow_spans.var_or_use();
676
677         let mut err = self.infcx
678             .tcx
679             .cannot_borrow_across_destructor(borrow_span, Origin::Mir);
680
681         let what_was_dropped = match self.describe_place(place) {
682             Some(name) => format!("`{}`", name.as_str()),
683             None => format!("temporary value"),
684         };
685
686         let label = match self.describe_place(&borrow.borrowed_place) {
687             Some(borrowed) => format!(
688                 "here, drop of {D} needs exclusive access to `{B}`, \
689                  because the type `{T}` implements the `Drop` trait",
690                 D = what_was_dropped,
691                 T = dropped_ty,
692                 B = borrowed
693             ),
694             None => format!(
695                 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
696                 D = what_was_dropped,
697                 T = dropped_ty
698             ),
699         };
700         err.span_label(drop_span, label);
701
702         // Only give this note and suggestion if they could be relevant.
703         let explanation =
704             self.explain_why_borrow_contains_point(context, borrow, kind.map(|k| (k, place)));
705         match explanation {
706             BorrowExplanation::UsedLater { .. }
707             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
708                 err.note("consider using a `let` binding to create a longer lived value");
709             }
710             _ => {}
711         }
712
713         explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
714
715         err.buffer(&mut self.errors_buffer);
716     }
717
718     fn report_thread_local_value_does_not_live_long_enough(
719         &mut self,
720         drop_span: Span,
721         borrow_span: Span,
722     ) -> DiagnosticBuilder<'cx> {
723         debug!(
724             "report_thread_local_value_does_not_live_long_enough(\
725              {:?}, {:?}\
726              )",
727             drop_span, borrow_span
728         );
729
730         let mut err = self.infcx
731             .tcx
732             .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
733
734         err.span_label(
735             borrow_span,
736             "thread-local variables cannot be borrowed beyond the end of the function",
737         );
738         err.span_label(drop_span, "end of enclosing function is here");
739
740         err
741     }
742
743     fn report_temporary_value_does_not_live_long_enough(
744         &mut self,
745         context: Context,
746         scope_tree: &Lrc<ScopeTree>,
747         borrow: &BorrowData<'tcx>,
748         drop_span: Span,
749         borrow_spans: UseSpans,
750         proper_span: Span,
751     ) -> DiagnosticBuilder<'cx> {
752         debug!(
753             "report_temporary_value_does_not_live_long_enough(\
754              {:?}, {:?}, {:?}, {:?}, {:?}\
755              )",
756             context, scope_tree, borrow, drop_span, proper_span
757         );
758
759         let tcx = self.infcx.tcx;
760         let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
761         err.span_label(
762             proper_span,
763             "creates a temporary which is freed while still in use",
764         );
765         err.span_label(
766             drop_span,
767             "temporary value is freed at the end of this statement",
768         );
769
770         let explanation = self.explain_why_borrow_contains_point(context, borrow, None);
771         match explanation {
772             BorrowExplanation::UsedLater(..)
773             | BorrowExplanation::UsedLaterInLoop(..)
774             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
775                 // Only give this note and suggestion if it could be relevant.
776                 err.note("consider using a `let` binding to create a longer lived value");
777             }
778             _ => {}
779         }
780         explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
781
782         borrow_spans.args_span_label(&mut err, "value captured here");
783
784         err
785     }
786
787     fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveSite> {
788         let mir = self.mir;
789
790         let mut stack = Vec::new();
791         stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| {
792             let is_back_edge = context.loc.dominates(predecessor, &self.dominators);
793             (predecessor, is_back_edge)
794         }));
795
796         let mut visited = FxHashSet();
797         let mut result = vec![];
798
799         'dfs: while let Some((location, is_back_edge)) = stack.pop() {
800             debug!(
801                 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
802                 location, is_back_edge
803             );
804
805             if !visited.insert(location) {
806                 continue;
807             }
808
809             // check for moves
810             let stmt_kind = mir[location.block]
811                 .statements
812                 .get(location.statement_index)
813                 .map(|s| &s.kind);
814             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
815                 // this analysis only tries to find moves explicitly
816                 // written by the user, so we ignore the move-outs
817                 // created by `StorageDead` and at the beginning
818                 // of a function.
819             } else {
820                 // If we are found a use of a.b.c which was in error, then we want to look for
821                 // moves not only of a.b.c but also a.b and a.
822                 //
823                 // Note that the moves data already includes "parent" paths, so we don't have to
824                 // worry about the other case: that is, if there is a move of a.b.c, it is already
825                 // marked as a move of a.b and a as well, so we will generate the correct errors
826                 // there.
827                 let mut mpis = vec![mpi];
828                 let move_paths = &self.move_data.move_paths;
829                 mpis.extend(move_paths[mpi].parents(move_paths));
830
831                 for moi in &self.move_data.loc_map[location] {
832                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
833                     if mpis.contains(&self.move_data.moves[*moi].path) {
834                         debug!("report_use_of_moved_or_uninitialized: found");
835                         result.push(MoveSite {
836                             moi: *moi,
837                             traversed_back_edge: is_back_edge,
838                         });
839
840                         // Strictly speaking, we could continue our DFS here. There may be
841                         // other moves that can reach the point of error. But it is kind of
842                         // confusing to highlight them.
843                         //
844                         // Example:
845                         //
846                         // ```
847                         // let a = vec![];
848                         // let b = a;
849                         // let c = a;
850                         // drop(a); // <-- current point of error
851                         // ```
852                         //
853                         // Because we stop the DFS here, we only highlight `let c = a`,
854                         // and not `let b = a`. We will of course also report an error at
855                         // `let c = a` which highlights `let b = a` as the move.
856                         continue 'dfs;
857                     }
858                 }
859             }
860
861             // check for inits
862             let mut any_match = false;
863             drop_flag_effects::for_location_inits(
864                 self.infcx.tcx,
865                 self.mir,
866                 self.move_data,
867                 location,
868                 |m| {
869                     if m == mpi {
870                         any_match = true;
871                     }
872                 },
873             );
874             if any_match {
875                 continue 'dfs;
876             }
877
878             stack.extend(mir.predecessor_locations(location).map(|predecessor| {
879                 let back_edge = location.dominates(predecessor, &self.dominators);
880                 (predecessor, is_back_edge || back_edge)
881             }));
882         }
883
884         result
885     }
886
887     pub(super) fn report_illegal_mutation_of_borrowed(
888         &mut self,
889         context: Context,
890         (place, span): (&Place<'tcx>, Span),
891         loan: &BorrowData<'tcx>,
892     ) {
893         let loan_spans = self.retrieve_borrow_spans(loan);
894         let loan_span = loan_spans.args_or_use();
895
896         let tcx = self.infcx.tcx;
897         let mut err = if loan.kind == BorrowKind::Shallow {
898             tcx.cannot_mutate_in_match_guard(
899                 span,
900                 loan_span,
901                 &self.describe_place(place).unwrap_or("_".to_owned()),
902                 "assign",
903                 Origin::Mir,
904             )
905         } else {
906             tcx.cannot_assign_to_borrowed(
907                 span,
908                 loan_span,
909                 &self.describe_place(place).unwrap_or("_".to_owned()),
910                 Origin::Mir,
911             )
912         };
913
914         loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
915
916         self.explain_why_borrow_contains_point(context, loan, None)
917             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "");
918
919         err.buffer(&mut self.errors_buffer);
920     }
921
922     /// Reports an illegal reassignment; for example, an assignment to
923     /// (part of) a non-`mut` local that occurs potentially after that
924     /// local has already been initialized. `place` is the path being
925     /// assigned; `err_place` is a place providing a reason why
926     /// `place` is not mutable (e.g. the non-`mut` local `x` in an
927     /// assignment to `x.f`).
928     pub(super) fn report_illegal_reassignment(
929         &mut self,
930         _context: Context,
931         (place, span): (&Place<'tcx>, Span),
932         assigned_span: Span,
933         err_place: &Place<'tcx>,
934     ) {
935         let (from_arg, local_decl) = if let Place::Local(local) = *err_place {
936             if let LocalKind::Arg = self.mir.local_kind(local) {
937                 (true, Some(&self.mir.local_decls[local]))
938             } else {
939                 (false, Some(&self.mir.local_decls[local]))
940             }
941         } else {
942             (false, None)
943         };
944
945         // If root local is initialized immediately (everything apart from let
946         // PATTERN;) then make the error refer to that local, rather than the
947         // place being assigned later.
948         let (place_description, assigned_span) = match local_decl {
949             Some(LocalDecl {
950                 is_user_variable: Some(ClearCrossCrate::Clear),
951                 ..
952             })
953             | Some(LocalDecl {
954                 is_user_variable:
955                     Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
956                         opt_match_place: None,
957                         ..
958                     }))),
959                 ..
960             })
961             | Some(LocalDecl {
962                 is_user_variable: None,
963                 ..
964             })
965             | None => (self.describe_place(place), assigned_span),
966             Some(decl) => (self.describe_place(err_place), decl.source_info.span),
967         };
968
969         let mut err = self.infcx.tcx.cannot_reassign_immutable(
970             span,
971             place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
972             from_arg,
973             Origin::Mir,
974         );
975         let msg = if from_arg {
976             "cannot assign to immutable argument"
977         } else {
978             "cannot assign twice to immutable variable"
979         };
980         if span != assigned_span {
981             if !from_arg {
982                 let value_msg = match place_description {
983                     Some(name) => format!("`{}`", name),
984                     None => "value".to_owned(),
985                 };
986                 err.span_label(assigned_span, format!("first assignment to {}", value_msg));
987             }
988         }
989         if let Some(decl) = local_decl {
990             if let Some(name) = decl.name {
991                 if decl.can_be_made_mutable() {
992                     err.span_suggestion_with_applicability(
993                         decl.source_info.span,
994                         "make this binding mutable",
995                         format!("mut {}", name),
996                         Applicability::MachineApplicable,
997                     );
998                 }
999             }
1000         }
1001         err.span_label(span, msg);
1002         err.buffer(&mut self.errors_buffer);
1003     }
1004 }
1005
1006 pub(super) struct IncludingDowncast(bool);
1007
1008 /// Which case a StorageDeadOrDrop is for.
1009 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1010 enum StorageDeadOrDrop<'tcx> {
1011     LocalStorageDead,
1012     BoxedStorageDead,
1013     Destructor(ty::Ty<'tcx>),
1014 }
1015
1016 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1017     // End-user visible description of `place` if one can be found. If the
1018     // place is a temporary for instance, None will be returned.
1019     pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
1020         self.describe_place_with_options(place, IncludingDowncast(false))
1021     }
1022
1023     // End-user visible description of `place` if one can be found. If the
1024     // place is a temporary for instance, None will be returned.
1025     // `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
1026     // `Downcast` and `IncludingDowncast` is true
1027     pub(super) fn describe_place_with_options(
1028         &self,
1029         place: &Place<'tcx>,
1030         including_downcast: IncludingDowncast,
1031     ) -> Option<String> {
1032         let mut buf = String::new();
1033         match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
1034             Ok(()) => Some(buf),
1035             Err(()) => None,
1036         }
1037     }
1038
1039     // Appends end-user visible description of `place` to `buf`.
1040     fn append_place_to_string(
1041         &self,
1042         place: &Place<'tcx>,
1043         buf: &mut String,
1044         mut autoderef: bool,
1045         including_downcast: &IncludingDowncast,
1046     ) -> Result<(), ()> {
1047         match *place {
1048             Place::Promoted(_) => {
1049                 buf.push_str("promoted");
1050             }
1051             Place::Local(local) => {
1052                 self.append_local_to_string(local, buf)?;
1053             }
1054             Place::Static(ref static_) => {
1055                 buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
1056             }
1057             Place::Projection(ref proj) => {
1058                 match proj.elem {
1059                     ProjectionElem::Deref => {
1060                         let upvar_field_projection =
1061                             place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
1062                         if let Some(field) = upvar_field_projection {
1063                             let var_index = field.index();
1064                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
1065                             if self.mir.upvar_decls[var_index].by_ref {
1066                                 buf.push_str(&name);
1067                             } else {
1068                                 buf.push_str(&format!("*{}", &name));
1069                             }
1070                         } else {
1071                             if autoderef {
1072                                 self.append_place_to_string(
1073                                     &proj.base,
1074                                     buf,
1075                                     autoderef,
1076                                     &including_downcast,
1077                                 )?;
1078                             } else if let Place::Local(local) = proj.base {
1079                                 if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
1080                                     self.mir.local_decls[local].is_user_variable
1081                                 {
1082                                     self.append_place_to_string(
1083                                         &proj.base,
1084                                         buf,
1085                                         autoderef,
1086                                         &including_downcast,
1087                                     )?;
1088                                 } else {
1089                                     buf.push_str(&"*");
1090                                     self.append_place_to_string(
1091                                         &proj.base,
1092                                         buf,
1093                                         autoderef,
1094                                         &including_downcast,
1095                                     )?;
1096                                 }
1097                             } else {
1098                                 buf.push_str(&"*");
1099                                 self.append_place_to_string(
1100                                     &proj.base,
1101                                     buf,
1102                                     autoderef,
1103                                     &including_downcast,
1104                                 )?;
1105                             }
1106                         }
1107                     }
1108                     ProjectionElem::Downcast(..) => {
1109                         self.append_place_to_string(
1110                             &proj.base,
1111                             buf,
1112                             autoderef,
1113                             &including_downcast,
1114                         )?;
1115                         if including_downcast.0 {
1116                             return Err(());
1117                         }
1118                     }
1119                     ProjectionElem::Field(field, _ty) => {
1120                         autoderef = true;
1121
1122                         let upvar_field_projection =
1123                             place.is_upvar_field_projection(self.mir, &self.infcx.tcx);
1124                         if let Some(field) = upvar_field_projection {
1125                             let var_index = field.index();
1126                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
1127                             buf.push_str(&name);
1128                         } else {
1129                             let field_name = self.describe_field(&proj.base, field);
1130                             self.append_place_to_string(
1131                                 &proj.base,
1132                                 buf,
1133                                 autoderef,
1134                                 &including_downcast,
1135                             )?;
1136                             buf.push_str(&format!(".{}", field_name));
1137                         }
1138                     }
1139                     ProjectionElem::Index(index) => {
1140                         autoderef = true;
1141
1142                         self.append_place_to_string(
1143                             &proj.base,
1144                             buf,
1145                             autoderef,
1146                             &including_downcast,
1147                         )?;
1148                         buf.push_str("[");
1149                         if self.append_local_to_string(index, buf).is_err() {
1150                             buf.push_str("..");
1151                         }
1152                         buf.push_str("]");
1153                     }
1154                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1155                         autoderef = true;
1156                         // Since it isn't possible to borrow an element on a particular index and
1157                         // then use another while the borrow is held, don't output indices details
1158                         // to avoid confusing the end-user
1159                         self.append_place_to_string(
1160                             &proj.base,
1161                             buf,
1162                             autoderef,
1163                             &including_downcast,
1164                         )?;
1165                         buf.push_str(&"[..]");
1166                     }
1167                 };
1168             }
1169         }
1170
1171         Ok(())
1172     }
1173
1174     // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
1175     // a name, then `Err` is returned
1176     fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
1177         let local = &self.mir.local_decls[local_index];
1178         match local.name {
1179             Some(name) => {
1180                 buf.push_str(&name.to_string());
1181                 Ok(())
1182             }
1183             None => Err(()),
1184         }
1185     }
1186
1187     // End-user visible description of the `field`nth field of `base`
1188     fn describe_field(&self, base: &Place, field: Field) -> String {
1189         match *base {
1190             Place::Local(local) => {
1191                 let local = &self.mir.local_decls[local];
1192                 self.describe_field_from_ty(&local.ty, field)
1193             }
1194             Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field),
1195             Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
1196             Place::Projection(ref proj) => match proj.elem {
1197                 ProjectionElem::Deref => self.describe_field(&proj.base, field),
1198                 ProjectionElem::Downcast(def, variant_index) => format!(
1199                     "{}",
1200                     def.variants[variant_index].fields[field.index()].ident
1201                 ),
1202                 ProjectionElem::Field(_, field_type) => {
1203                     self.describe_field_from_ty(&field_type, field)
1204                 }
1205                 ProjectionElem::Index(..)
1206                 | ProjectionElem::ConstantIndex { .. }
1207                 | ProjectionElem::Subslice { .. } => {
1208                     self.describe_field(&proj.base, field).to_string()
1209                 }
1210             },
1211         }
1212     }
1213
1214     // End-user visible description of the `field_index`nth field of `ty`
1215     fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
1216         if ty.is_box() {
1217             // If the type is a box, the field is described from the boxed type
1218             self.describe_field_from_ty(&ty.boxed_ty(), field)
1219         } else {
1220             match ty.sty {
1221                 ty::Adt(def, _) => if def.is_enum() {
1222                     field.index().to_string()
1223                 } else {
1224                     def.non_enum_variant().fields[field.index()]
1225                         .ident
1226                         .to_string()
1227                 },
1228                 ty::Tuple(_) => field.index().to_string(),
1229                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
1230                     self.describe_field_from_ty(&ty, field)
1231                 }
1232                 ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field),
1233                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
1234                     // Convert the def-id into a node-id. node-ids are only valid for
1235                     // the local code in the current crate, so this returns an `Option` in case
1236                     // the closure comes from another crate. But in that case we wouldn't
1237                     // be borrowck'ing it, so we can just unwrap:
1238                     let node_id = self.infcx.tcx.hir.as_local_node_id(def_id).unwrap();
1239                     let freevar = self.infcx
1240                         .tcx
1241                         .with_freevars(node_id, |fv| fv[field.index()]);
1242
1243                     self.infcx.tcx.hir.name(freevar.var_id()).to_string()
1244                 }
1245                 _ => {
1246                     // Might need a revision when the fields in trait RFC is implemented
1247                     // (https://github.com/rust-lang/rfcs/pull/1546)
1248                     bug!(
1249                         "End-user description not implemented for field access on `{:?}`",
1250                         ty.sty
1251                     );
1252                 }
1253             }
1254         }
1255     }
1256
1257     // Retrieve type of a place for the current MIR representation
1258     fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option<ty::Ty> {
1259         match place {
1260             Place::Local(local) => {
1261                 let local = &self.mir.local_decls[*local];
1262                 Some(local.ty)
1263             }
1264             Place::Promoted(ref prom) => Some(prom.1),
1265             Place::Static(ref st) => Some(st.ty),
1266             Place::Projection(ref proj) => match proj.elem {
1267                 ProjectionElem::Field(_, ty) => Some(ty),
1268                 _ => None,
1269             },
1270         }
1271     }
1272
1273     /// Check if a place is a thread-local static.
1274     pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
1275         if let Place::Static(statik) = place {
1276             let attrs = self.infcx.tcx.get_attrs(statik.def_id);
1277             let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
1278
1279             debug!(
1280                 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
1281                 attrs, is_thread_local
1282             );
1283             is_thread_local
1284         } else {
1285             debug!("is_place_thread_local: no");
1286             false
1287         }
1288     }
1289
1290     fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
1291         let tcx = self.infcx.tcx;
1292         match place {
1293             Place::Local(_) | Place::Static(_) | Place::Promoted(_) => {
1294                 StorageDeadOrDrop::LocalStorageDead
1295             }
1296             Place::Projection(box PlaceProjection { base, elem }) => {
1297                 let base_access = self.classify_drop_access_kind(base);
1298                 match elem {
1299                     ProjectionElem::Deref => match base_access {
1300                         StorageDeadOrDrop::LocalStorageDead
1301                         | StorageDeadOrDrop::BoxedStorageDead => {
1302                             assert!(
1303                                 base.ty(self.mir, tcx).to_ty(tcx).is_box(),
1304                                 "Drop of value behind a reference or raw pointer"
1305                             );
1306                             StorageDeadOrDrop::BoxedStorageDead
1307                         }
1308                         StorageDeadOrDrop::Destructor(_) => base_access,
1309                     },
1310                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
1311                         let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
1312                         match base_ty.sty {
1313                             ty::Adt(def, _) if def.has_dtor(tcx) => {
1314                                 // Report the outermost adt with a destructor
1315                                 match base_access {
1316                                     StorageDeadOrDrop::Destructor(_) => base_access,
1317                                     StorageDeadOrDrop::LocalStorageDead
1318                                     | StorageDeadOrDrop::BoxedStorageDead => {
1319                                         StorageDeadOrDrop::Destructor(base_ty)
1320                                     }
1321                                 }
1322                             }
1323                             _ => base_access,
1324                         }
1325                     }
1326
1327                     ProjectionElem::ConstantIndex { .. }
1328                     | ProjectionElem::Subslice { .. }
1329                     | ProjectionElem::Index(_) => base_access,
1330                 }
1331             }
1332         }
1333     }
1334
1335     /// Annotate argument and return type of function and closure with (synthesized) lifetime for
1336     /// borrow of local value that does not live long enough.
1337     fn annotate_argument_and_return_for_borrow(
1338         &self,
1339         borrow: &BorrowData<'tcx>,
1340     ) -> Option<AnnotatedBorrowFnSignature> {
1341         // Define a fallback for when we can't match a closure.
1342         let fallback = || {
1343             let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
1344             if is_closure {
1345                 None
1346             } else {
1347                 let ty = self.infcx.tcx.type_of(self.mir_def_id);
1348                 match ty.sty {
1349                     ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) => self.annotate_fn_sig(
1350                         self.mir_def_id,
1351                         self.infcx.tcx.fn_sig(self.mir_def_id),
1352                     ),
1353                     _ => None,
1354                 }
1355             }
1356         };
1357
1358         // In order to determine whether we need to annotate, we need to check whether the reserve
1359         // place was an assignment into a temporary.
1360         //
1361         // If it was, we check whether or not that temporary is eventually assigned into the return
1362         // place. If it was, we can add annotations about the function's return type and arguments
1363         // and it'll make sense.
1364         let location = borrow.reserve_location;
1365         debug!(
1366             "annotate_argument_and_return_for_borrow: location={:?}",
1367             location
1368         );
1369         match &self.mir[location.block]
1370             .statements
1371             .get(location.statement_index)
1372         {
1373             Some(&Statement {
1374                 kind: StatementKind::Assign(ref reservation, _),
1375                 ..
1376             }) => {
1377                 debug!(
1378                     "annotate_argument_and_return_for_borrow: reservation={:?}",
1379                     reservation
1380                 );
1381                 // Check that the initial assignment of the reserve location is into a temporary.
1382                 let mut target = *match reservation {
1383                     Place::Local(local) if self.mir.local_kind(*local) == LocalKind::Temp => local,
1384                     _ => return None,
1385                 };
1386
1387                 // Next, look through the rest of the block, checking if we are assigning the
1388                 // `target` (that is, the place that contains our borrow) to anything.
1389                 let mut annotated_closure = None;
1390                 for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1391                     debug!(
1392                         "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
1393                         target, stmt
1394                     );
1395                     if let StatementKind::Assign(Place::Local(assigned_to), box rvalue) = &stmt.kind
1396                     {
1397                         debug!(
1398                             "annotate_argument_and_return_for_borrow: assigned_to={:?} \
1399                              rvalue={:?}",
1400                             assigned_to, rvalue
1401                         );
1402                         // Check if our `target` was captured by a closure.
1403                         if let Rvalue::Aggregate(
1404                             box AggregateKind::Closure(def_id, substs),
1405                             operands,
1406                         ) = rvalue
1407                         {
1408                             for operand in operands {
1409                                 let assigned_from = match operand {
1410                                     Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1411                                         assigned_from
1412                                     }
1413                                     _ => continue,
1414                                 };
1415                                 debug!(
1416                                     "annotate_argument_and_return_for_borrow: assigned_from={:?}",
1417                                     assigned_from
1418                                 );
1419
1420                                 // Find the local from the operand.
1421                                 let assigned_from_local = match assigned_from.local() {
1422                                     Some(local) => local,
1423                                     None => continue,
1424                                 };
1425
1426                                 if assigned_from_local != target {
1427                                     continue;
1428                                 }
1429
1430                                 // If a closure captured our `target` and then assigned
1431                                 // into a place then we should annotate the closure in
1432                                 // case it ends up being assigned into the return place.
1433                                 annotated_closure = self.annotate_fn_sig(
1434                                     *def_id,
1435                                     self.infcx.closure_sig(*def_id, *substs),
1436                                 );
1437                                 debug!(
1438                                     "annotate_argument_and_return_for_borrow: \
1439                                      annotated_closure={:?} assigned_from_local={:?} \
1440                                      assigned_to={:?}",
1441                                     annotated_closure, assigned_from_local, assigned_to
1442                                 );
1443
1444                                 if *assigned_to == mir::RETURN_PLACE {
1445                                     // If it was assigned directly into the return place, then
1446                                     // return now.
1447                                     return annotated_closure;
1448                                 } else {
1449                                     // Otherwise, update the target.
1450                                     target = *assigned_to;
1451                                 }
1452                             }
1453
1454                             // If none of our closure's operands matched, then skip to the next
1455                             // statement.
1456                             continue;
1457                         }
1458
1459                         // Otherwise, look at other types of assignment.
1460                         let assigned_from = match rvalue {
1461                             Rvalue::Ref(_, _, assigned_from) => assigned_from,
1462                             Rvalue::Use(operand) => match operand {
1463                                 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1464                                     assigned_from
1465                                 }
1466                                 _ => continue,
1467                             },
1468                             _ => continue,
1469                         };
1470                         debug!(
1471                             "annotate_argument_and_return_for_borrow: \
1472                              assigned_from={:?}",
1473                             assigned_from,
1474                         );
1475
1476                         // Find the local from the rvalue.
1477                         let assigned_from_local = match assigned_from.local() {
1478                             Some(local) => local,
1479                             None => continue,
1480                         };
1481                         debug!(
1482                             "annotate_argument_and_return_for_borrow: \
1483                              assigned_from_local={:?}",
1484                             assigned_from_local,
1485                         );
1486
1487                         // Check if our local matches the target - if so, we've assigned our
1488                         // borrow to a new place.
1489                         if assigned_from_local != target {
1490                             continue;
1491                         }
1492
1493                         // If we assigned our `target` into a new place, then we should
1494                         // check if it was the return place.
1495                         debug!(
1496                             "annotate_argument_and_return_for_borrow: \
1497                              assigned_from_local={:?} assigned_to={:?}",
1498                             assigned_from_local, assigned_to
1499                         );
1500                         if *assigned_to == mir::RETURN_PLACE {
1501                             // If it was then return the annotated closure if there was one,
1502                             // else, annotate this function.
1503                             return annotated_closure.or_else(fallback);
1504                         }
1505
1506                         // If we didn't assign into the return place, then we just update
1507                         // the target.
1508                         target = *assigned_to;
1509                     }
1510                 }
1511
1512                 // Check the terminator if we didn't find anything in the statements.
1513                 let terminator = &self.mir[location.block].terminator();
1514                 debug!(
1515                     "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
1516                     target, terminator
1517                 );
1518                 if let TerminatorKind::Call {
1519                     destination: Some((Place::Local(assigned_to), _)),
1520                     args,
1521                     ..
1522                 } = &terminator.kind
1523                 {
1524                     debug!(
1525                         "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
1526                         assigned_to, args
1527                     );
1528                     for operand in args {
1529                         let assigned_from = match operand {
1530                             Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1531                                 assigned_from
1532                             }
1533                             _ => continue,
1534                         };
1535                         debug!(
1536                             "annotate_argument_and_return_for_borrow: assigned_from={:?}",
1537                             assigned_from,
1538                         );
1539
1540                         if let Some(assigned_from_local) = assigned_from.local() {
1541                             debug!(
1542                                 "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
1543                                 assigned_from_local,
1544                             );
1545
1546                             if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
1547                                 return annotated_closure.or_else(fallback);
1548                             }
1549                         }
1550                     }
1551                 }
1552             }
1553             _ => {}
1554         }
1555
1556         // If we haven't found an assignment into the return place, then we need not add
1557         // any annotations.
1558         debug!("annotate_argument_and_return_for_borrow: none found");
1559         None
1560     }
1561
1562     /// Annotate the first argument and return type of a function signature if they are
1563     /// references.
1564     fn annotate_fn_sig(
1565         &self,
1566         did: DefId,
1567         sig: ty::PolyFnSig<'tcx>,
1568     ) -> Option<AnnotatedBorrowFnSignature> {
1569         debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
1570         let is_closure = self.infcx.tcx.is_closure(did);
1571         let fn_node_id = self.infcx.tcx.hir.as_local_node_id(did)?;
1572         let fn_decl = self.infcx.tcx.hir.fn_decl(fn_node_id)?;
1573
1574         // We need to work out which arguments to highlight. We do this by looking
1575         // at the return type, where there are three cases:
1576         //
1577         // 1. If there are named arguments, then we should highlight the return type and
1578         //    highlight any of the arguments that are also references with that lifetime.
1579         //    If there are no arguments that have the same lifetime as the return type,
1580         //    then don't highlight anything.
1581         // 2. The return type is a reference with an anonymous lifetime. If this is
1582         //    the case, then we can take advantage of (and teach) the lifetime elision
1583         //    rules.
1584         //
1585         //    We know that an error is being reported. So the arguments and return type
1586         //    must satisfy the elision rules. Therefore, if there is a single argument
1587         //    then that means the return type and first (and only) argument have the same
1588         //    lifetime and the borrow isn't meeting that, we can highlight the argument
1589         //    and return type.
1590         //
1591         //    If there are multiple arguments then the first argument must be self (else
1592         //    it would not satisfy the elision rules), so we can highlight self and the
1593         //    return type.
1594         // 3. The return type is not a reference. In this case, we don't highlight
1595         //    anything.
1596         let return_ty = sig.output();
1597         match return_ty.skip_binder().sty {
1598             ty::TyKind::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
1599                 // This is case 1 from above, return type is a named reference so we need to
1600                 // search for relevant arguments.
1601                 let mut arguments = Vec::new();
1602                 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
1603                     if let ty::TyKind::Ref(argument_region, _, _) = argument.sty {
1604                         if argument_region == return_region {
1605                             // Need to use the `rustc::ty` types to compare against the
1606                             // `return_region`. Then use the `rustc::hir` type to get only
1607                             // the lifetime span.
1608                             match &fn_decl.inputs[index].node {
1609                                 hir::TyKind::Rptr(lifetime, _) => {
1610                                     // With access to the lifetime, we can get
1611                                     // the span of it.
1612                                     arguments.push((*argument, lifetime.span));
1613                                 }
1614                                 _ => bug!("ty type is a ref but hir type is not"),
1615                             }
1616                         }
1617                     }
1618                 }
1619
1620                 // We need to have arguments. This shouldn't happen, but it's worth checking.
1621                 if arguments.is_empty() {
1622                     return None;
1623                 }
1624
1625                 // We use a mix of the HIR and the Ty types to get information
1626                 // as the HIR doesn't have full types for closure arguments.
1627                 let return_ty = *sig.output().skip_binder();
1628                 let mut return_span = fn_decl.output.span();
1629                 if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
1630                     if let hir::TyKind::Rptr(lifetime, _) = ty.into_inner().node {
1631                         return_span = lifetime.span;
1632                     }
1633                 }
1634
1635                 Some(AnnotatedBorrowFnSignature::NamedFunction {
1636                     arguments,
1637                     return_ty,
1638                     return_span,
1639                 })
1640             }
1641             ty::TyKind::Ref(_, _, _) if is_closure => {
1642                 // This is case 2 from above but only for closures, return type is anonymous
1643                 // reference so we select
1644                 // the first argument.
1645                 let argument_span = fn_decl.inputs.first()?.span;
1646                 let argument_ty = sig.inputs().skip_binder().first()?;
1647
1648                 // Closure arguments are wrapped in a tuple, so we need to get the first
1649                 // from that.
1650                 if let ty::TyKind::Tuple(elems) = argument_ty.sty {
1651                     let argument_ty = elems.first()?;
1652                     if let ty::TyKind::Ref(_, _, _) = argument_ty.sty {
1653                         return Some(AnnotatedBorrowFnSignature::Closure {
1654                             argument_ty,
1655                             argument_span,
1656                         });
1657                     }
1658                 }
1659
1660                 None
1661             }
1662             ty::TyKind::Ref(_, _, _) => {
1663                 // This is also case 2 from above but for functions, return type is still an
1664                 // anonymous reference so we select the first argument.
1665                 let argument_span = fn_decl.inputs.first()?.span;
1666                 let argument_ty = sig.inputs().skip_binder().first()?;
1667
1668                 let return_span = fn_decl.output.span();
1669                 let return_ty = *sig.output().skip_binder();
1670
1671                 // We expect the first argument to be a reference.
1672                 match argument_ty.sty {
1673                     ty::TyKind::Ref(_, _, _) => {}
1674                     _ => return None,
1675                 }
1676
1677                 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
1678                     argument_ty,
1679                     argument_span,
1680                     return_ty,
1681                     return_span,
1682                 })
1683             }
1684             _ => {
1685                 // This is case 3 from above, return type is not a reference so don't highlight
1686                 // anything.
1687                 None
1688             }
1689         }
1690     }
1691 }
1692
1693 #[derive(Debug)]
1694 enum AnnotatedBorrowFnSignature<'tcx> {
1695     NamedFunction {
1696         arguments: Vec<(ty::Ty<'tcx>, Span)>,
1697         return_ty: ty::Ty<'tcx>,
1698         return_span: Span,
1699     },
1700     AnonymousFunction {
1701         argument_ty: ty::Ty<'tcx>,
1702         argument_span: Span,
1703         return_ty: ty::Ty<'tcx>,
1704         return_span: Span,
1705     },
1706     Closure {
1707         argument_ty: ty::Ty<'tcx>,
1708         argument_span: Span,
1709     },
1710 }
1711
1712 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
1713     /// Annotate the provided diagnostic with information about borrow from the fn signature that
1714     /// helps explain.
1715     fn emit(&self, diag: &mut DiagnosticBuilder<'_>) -> String {
1716         match self {
1717             AnnotatedBorrowFnSignature::Closure {
1718                 argument_ty,
1719                 argument_span,
1720             } => {
1721                 diag.span_label(
1722                     *argument_span,
1723                     format!("has type `{}`", self.get_name_for_ty(argument_ty, 0)),
1724                 );
1725
1726                 self.get_region_name_for_ty(argument_ty, 0)
1727             }
1728             AnnotatedBorrowFnSignature::AnonymousFunction {
1729                 argument_ty,
1730                 argument_span,
1731                 return_ty,
1732                 return_span,
1733             } => {
1734                 let argument_ty_name = self.get_name_for_ty(argument_ty, 0);
1735                 diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
1736
1737                 let return_ty_name = self.get_name_for_ty(return_ty, 0);
1738                 let types_equal = return_ty_name == argument_ty_name;
1739                 diag.span_label(
1740                     *return_span,
1741                     format!(
1742                         "{}has type `{}`",
1743                         if types_equal { "also " } else { "" },
1744                         return_ty_name,
1745                     ),
1746                 );
1747
1748                 diag.note(
1749                     "argument and return type have the same lifetime due to lifetime elision rules",
1750                 );
1751                 diag.note(
1752                     "to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch10-03-\
1753                      lifetime-syntax.html#lifetime-elision>",
1754                 );
1755
1756                 self.get_region_name_for_ty(return_ty, 0)
1757             }
1758             AnnotatedBorrowFnSignature::NamedFunction {
1759                 arguments,
1760                 return_ty,
1761                 return_span,
1762             } => {
1763                 // Region of return type and arguments checked to be the same earlier.
1764                 let region_name = self.get_region_name_for_ty(return_ty, 0);
1765                 for (_, argument_span) in arguments {
1766                     diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
1767                 }
1768
1769                 diag.span_label(
1770                     *return_span,
1771                     format!("also has lifetime `{}`", region_name,),
1772                 );
1773
1774                 diag.help(&format!(
1775                     "use data from the highlighted arguments which match the `{}` lifetime of \
1776                      the return type",
1777                     region_name,
1778                 ));
1779
1780                 region_name
1781             }
1782         }
1783     }
1784
1785     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
1786     /// name where required.
1787     fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
1788         // We need to add synthesized lifetimes where appropriate. We do
1789         // this by hooking into the pretty printer and telling it to label the
1790         // lifetimes without names with the value `'0`.
1791         match ty.sty {
1792             ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
1793             | ty::TyKind::Ref(
1794                 ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }),
1795                 _,
1796                 _,
1797             ) => with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty)),
1798             _ => format!("{}", ty),
1799         }
1800     }
1801
1802     /// Return the name of the provided `Ty` (that must be a reference)'s region with a
1803     /// synthesized lifetime name where required.
1804     fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
1805         match ty.sty {
1806             ty::TyKind::Ref(region, _, _) => match region {
1807                 ty::RegionKind::ReLateBound(_, br)
1808                 | ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }) => {
1809                     with_highlight_region_for_bound_region(*br, counter, || format!("{}", region))
1810                 }
1811                 _ => format!("{}", region),
1812             },
1813             _ => bug!("ty for annotation of borrow region is not a reference"),
1814         }
1815     }
1816 }
1817
1818 // The span(s) associated to a use of a place.
1819 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1820 pub(super) enum UseSpans {
1821     // The access is caused by capturing a variable for a closure.
1822     ClosureUse {
1823         // The span of the args of the closure, including the `move` keyword if
1824         // it's present.
1825         args_span: Span,
1826         // The span of the first use of the captured variable inside the closure.
1827         var_span: Span,
1828     },
1829     // This access has a single span associated to it: common case.
1830     OtherUse(Span),
1831 }
1832
1833 impl UseSpans {
1834     pub(super) fn args_or_use(self) -> Span {
1835         match self {
1836             UseSpans::ClosureUse {
1837                 args_span: span, ..
1838             }
1839             | UseSpans::OtherUse(span) => span,
1840         }
1841     }
1842
1843     pub(super) fn var_or_use(self) -> Span {
1844         match self {
1845             UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
1846         }
1847     }
1848
1849     // Add a span label to the arguments of the closure, if it exists.
1850     pub(super) fn args_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
1851         if let UseSpans::ClosureUse { args_span, .. } = self {
1852             err.span_label(args_span, message);
1853         }
1854     }
1855
1856     // Add a span label to the use of the captured variable, if it exists.
1857     pub(super) fn var_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
1858         if let UseSpans::ClosureUse { var_span, .. } = self {
1859             err.span_label(var_span, message);
1860         }
1861     }
1862
1863     pub(super) fn for_closure(self) -> bool {
1864         match self {
1865             UseSpans::ClosureUse { .. } => true,
1866             UseSpans::OtherUse(_) => false,
1867         }
1868     }
1869
1870     pub(super) fn or_else<F>(self, if_other: F) -> Self
1871     where
1872         F: FnOnce() -> Self,
1873     {
1874         match self {
1875             closure @ UseSpans::ClosureUse { .. } => closure,
1876             UseSpans::OtherUse(_) => if_other(),
1877         }
1878     }
1879 }
1880
1881 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1882     /// Finds the spans associated to a move or copy of move_place at location.
1883     pub(super) fn move_spans(
1884         &self,
1885         moved_place: &Place<'tcx>, // Could also be an upvar.
1886         location: Location,
1887     ) -> UseSpans {
1888         use self::UseSpans::*;
1889         use rustc::hir::ExprKind::Closure;
1890         use rustc::mir::AggregateKind;
1891
1892         let stmt = match self.mir[location.block]
1893             .statements
1894             .get(location.statement_index)
1895         {
1896             Some(stmt) => stmt,
1897             None => return OtherUse(self.mir.source_info(location).span),
1898         };
1899
1900         if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
1901             if let AggregateKind::Closure(def_id, _) = **kind {
1902                 debug!("find_closure_move_span: found closure {:?}", places);
1903
1904                 if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
1905                     if let Closure(_, _, _, args_span, _) =
1906                         self.infcx.tcx.hir.expect_expr(node_id).node
1907                     {
1908                         if let Some(var_span) = self.infcx.tcx.with_freevars(node_id, |freevars| {
1909                             for (v, place) in freevars.iter().zip(places) {
1910                                 match place {
1911                                     Operand::Copy(place) | Operand::Move(place)
1912                                         if moved_place == place =>
1913                                     {
1914                                         debug!(
1915                                             "find_closure_move_span: found captured local {:?}",
1916                                             place
1917                                         );
1918                                         return Some(v.span);
1919                                     }
1920                                     _ => {}
1921                                 }
1922                             }
1923                             None
1924                         }) {
1925                             return ClosureUse {
1926                                 args_span,
1927                                 var_span,
1928                             };
1929                         }
1930                     }
1931                 }
1932             }
1933         }
1934
1935         return OtherUse(stmt.source_info.span);
1936     }
1937
1938     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
1939     /// and its usage of the local assigned at `location`.
1940     /// This is done by searching in statements succeeding `location`
1941     /// and originating from `maybe_closure_span`.
1942     pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
1943         use self::UseSpans::*;
1944         use rustc::hir::ExprKind::Closure;
1945
1946         let local = match self.mir[location.block]
1947             .statements
1948             .get(location.statement_index)
1949         {
1950             Some(&Statement {
1951                 kind: StatementKind::Assign(Place::Local(local), _),
1952                 ..
1953             }) => local,
1954             _ => return OtherUse(use_span),
1955         };
1956
1957         if self.mir.local_kind(local) != LocalKind::Temp {
1958             // operands are always temporaries.
1959             return OtherUse(use_span);
1960         }
1961
1962         for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1963             if let StatementKind::Assign(_, box Rvalue::Aggregate(ref kind, ref places)) = stmt.kind
1964             {
1965                 if let AggregateKind::Closure(def_id, _) = **kind {
1966                     debug!("find_closure_borrow_span: found closure {:?}", places);
1967
1968                     return if let Some(node_id) = self.infcx.tcx.hir.as_local_node_id(def_id) {
1969                         let args_span = if let Closure(_, _, _, span, _) =
1970                             self.infcx.tcx.hir.expect_expr(node_id).node
1971                         {
1972                             span
1973                         } else {
1974                             return OtherUse(use_span);
1975                         };
1976
1977                         self.infcx
1978                             .tcx
1979                             .with_freevars(node_id, |freevars| {
1980                                 for (v, place) in freevars.iter().zip(places) {
1981                                     match *place {
1982                                         Operand::Copy(Place::Local(l))
1983                                         | Operand::Move(Place::Local(l)) if local == l =>
1984                                         {
1985                                             debug!(
1986                                                 "find_closure_borrow_span: found captured local \
1987                                                  {:?}",
1988                                                 l
1989                                             );
1990                                             return Some(v.span);
1991                                         }
1992                                         _ => {}
1993                                     }
1994                                 }
1995                                 None
1996                             })
1997                             .map(|var_span| ClosureUse {
1998                                 args_span,
1999                                 var_span,
2000                             })
2001                             .unwrap_or(OtherUse(use_span))
2002                     } else {
2003                         OtherUse(use_span)
2004                     };
2005                 }
2006             }
2007
2008             if use_span != stmt.source_info.span {
2009                 break;
2010             }
2011         }
2012
2013         OtherUse(use_span)
2014     }
2015
2016     /// Helper to retrieve span(s) of given borrow from the current MIR
2017     /// representation
2018     pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData) -> UseSpans {
2019         let span = self.mir.source_info(borrow.reserve_location).span;
2020         self.borrow_spans(span, borrow.reserve_location)
2021     }
2022 }