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