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