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