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