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