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