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