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