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