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