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