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