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