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