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