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