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