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