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