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