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