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