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