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