]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/error_reporting.rs
Auto merge of #59445 - alexreg:ban-multi-trait-objects-via-aliases, r=oli-obk
[rust.git] / src / librustc_mir / borrow_check / error_reporting.rs
1 use crate::borrow_check::nll::explain_borrow::BorrowExplanation;
2 use crate::borrow_check::nll::region_infer::{RegionName, RegionNameSource};
3 use crate::borrow_check::prefixes::IsPrefixOf;
4 use crate::borrow_check::WriteKind;
5 use rustc::hir;
6 use rustc::hir::def::Namespace;
7 use rustc::hir::def_id::DefId;
8 use rustc::middle::region::ScopeTree;
9 use rustc::mir::{
10     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant,
11     ConstraintCategory, Field, Local, LocalDecl, LocalKind, Location, Operand,
12     Place, PlaceBase, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind,
13     Static, StaticKind, TerminatorKind, VarBindingForm,
14 };
15 use rustc::ty::{self, DefIdTree, Ty};
16 use rustc::ty::layout::VariantIdx;
17 use rustc::ty::print::Print;
18 use rustc_data_structures::fx::FxHashSet;
19 use rustc_data_structures::indexed_vec::Idx;
20 use rustc_errors::{Applicability, DiagnosticBuilder};
21 use syntax_pos::Span;
22 use syntax::source_map::CompilerDesugaringKind;
23 use syntax::symbol::sym;
24
25 use super::borrow_set::BorrowData;
26 use super::{MirBorrowckCtxt};
27 use super::{InitializationRequiringAction, PrefixSet};
28 use crate::dataflow::drop_flag_effects;
29 use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
30 use crate::util::borrowck_errors::{BorrowckErrors, Origin};
31
32 #[derive(Debug)]
33 struct MoveSite {
34     /// Index of the "move out" that we found. The `MoveData` can
35     /// then tell us where the move occurred.
36     moi: MoveOutIndex,
37
38     /// `true` if we traversed a back edge while walking from the point
39     /// of error to the move site.
40     traversed_back_edge: bool
41 }
42
43 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
44     pub(super) fn report_use_of_moved_or_uninitialized(
45         &mut self,
46         location: Location,
47         desired_action: InitializationRequiringAction,
48         (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
49         mpi: MovePathIndex,
50     ) {
51         debug!(
52             "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
53              moved_place={:?} used_place={:?} span={:?} mpi={:?}",
54             location, desired_action, moved_place, used_place, span, mpi
55         );
56
57         let use_spans = self.move_spans(moved_place, location)
58             .or_else(|| self.borrow_spans(span, location));
59         let span = use_spans.args_or_use();
60
61         let move_site_vec = self.get_moved_indexes(location, mpi);
62         debug!(
63             "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
64             move_site_vec
65         );
66         let move_out_indices: Vec<_> = move_site_vec
67             .iter()
68             .map(|move_site| move_site.moi)
69             .collect();
70
71         if move_out_indices.is_empty() {
72             let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
73
74             if self.uninitialized_error_reported.contains(root_place) {
75                 debug!(
76                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
77                     root_place
78                 );
79                 return;
80             }
81
82             self.uninitialized_error_reported.insert(root_place.clone());
83
84             let item_msg = match self.describe_place_with_options(used_place,
85                                                                   IncludingDowncast(true)) {
86                 Some(name) => format!("`{}`", name),
87                 None => "value".to_owned(),
88             };
89             let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
90                 span,
91                 desired_action.as_noun(),
92                 &self.describe_place_with_options(moved_place, IncludingDowncast(true))
93                     .unwrap_or_else(|| "_".to_owned()),
94                 Origin::Mir,
95             );
96             err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
97
98             use_spans.var_span_label(
99                 &mut err,
100                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
101             );
102
103             err.buffer(&mut self.errors_buffer);
104         } else {
105             if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
106                 if self.prefixes(&reported_place, PrefixSet::All)
107                     .any(|p| p == used_place)
108                 {
109                     debug!(
110                         "report_use_of_moved_or_uninitialized place: error suppressed \
111                          mois={:?}",
112                         move_out_indices
113                     );
114                     return;
115                 }
116             }
117
118             let msg = ""; //FIXME: add "partially " or "collaterally "
119
120             let mut err = self.infcx.tcx.cannot_act_on_moved_value(
121                 span,
122                 desired_action.as_noun(),
123                 msg,
124                 self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
125                 Origin::Mir,
126             );
127
128             self.add_moved_or_invoked_closure_note(
129                 location,
130                 used_place,
131                 &mut err,
132             );
133
134             let mut is_loop_move = false;
135             let is_partial_move = move_site_vec.iter().any(|move_site| {
136                 let move_out = self.move_data.moves[(*move_site).moi];
137                 let moved_place = &self.move_data.move_paths[move_out.path].place;
138                 used_place != moved_place && used_place.is_prefix_of(moved_place)
139             });
140             for move_site in &move_site_vec {
141                 let move_out = self.move_data.moves[(*move_site).moi];
142                 let moved_place = &self.move_data.move_paths[move_out.path].place;
143
144                 let move_spans = self.move_spans(moved_place, move_out.source);
145                 let move_span = move_spans.args_or_use();
146
147                 let move_msg = if move_spans.for_closure() {
148                     " into closure"
149                 } else {
150                     ""
151                 };
152
153                 if span == move_span {
154                     err.span_label(
155                         span,
156                         format!("value moved{} here, in previous iteration of loop", move_msg),
157                     );
158                     if Some(CompilerDesugaringKind::ForLoop) == span.compiler_desugaring_kind() {
159                         if let Ok(snippet) = self.infcx.tcx.sess.source_map()
160                             .span_to_snippet(span)
161                         {
162                             err.span_suggestion(
163                                 move_span,
164                                 "consider borrowing this to avoid moving it into the for loop",
165                                 format!("&{}", snippet),
166                                 Applicability::MaybeIncorrect,
167                             );
168                         }
169                     }
170                     is_loop_move = true;
171                 } else if move_site.traversed_back_edge {
172                     err.span_label(
173                         move_span,
174                         format!(
175                             "value moved{} here, in previous iteration of loop",
176                             move_msg
177                         ),
178                     );
179                 } else {
180                     err.span_label(move_span, format!("value moved{} here", move_msg));
181                     move_spans.var_span_label(
182                         &mut err,
183                         format!("variable moved due to use{}", move_spans.describe()),
184                     );
185                 };
186             }
187
188             use_spans.var_span_label(
189                 &mut err,
190                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
191             );
192
193             if !is_loop_move {
194                 err.span_label(
195                     span,
196                     format!(
197                         "value {} here {}",
198                         desired_action.as_verb_in_past_tense(),
199                         if is_partial_move { "after partial move" } else { "after move" },
200                     ),
201                 );
202             }
203
204             let ty = used_place.ty(self.mir, self.infcx.tcx).ty;
205             let needs_note = match ty.sty {
206                 ty::Closure(id, _) => {
207                     let tables = self.infcx.tcx.typeck_tables_of(id);
208                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap();
209
210                     tables.closure_kind_origins().get(hir_id).is_none()
211                 }
212                 _ => true,
213             };
214
215             if needs_note {
216                 let mpi = self.move_data.moves[move_out_indices[0]].path;
217                 let place = &self.move_data.move_paths[mpi].place;
218
219                 let ty = place.ty(self.mir, self.infcx.tcx).ty;
220                 let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
221                 let note_msg = match opt_name {
222                     Some(ref name) => format!("`{}`", name),
223                     None => "value".to_owned(),
224                 };
225                 if let ty::Param(param_ty) = ty.sty {
226                     let tcx = self.infcx.tcx;
227                     let generics = tcx.generics_of(self.mir_def_id);
228                     let def_id = generics.type_param(&param_ty, tcx).def_id;
229                     if let Some(sp) = tcx.hir().span_if_local(def_id) {
230                         err.span_label(
231                             sp,
232                             "consider adding a `Copy` constraint to this type argument",
233                         );
234                     }
235                 }
236                 if let Place::Base(PlaceBase::Local(local)) = place {
237                     let decl = &self.mir.local_decls[*local];
238                     err.span_label(
239                         decl.source_info.span,
240                         format!(
241                             "move occurs because {} has type `{}`, \
242                                 which does not implement the `Copy` trait",
243                             note_msg, ty,
244                     ));
245                 } else {
246                     err.note(&format!(
247                         "move occurs because {} has type `{}`, \
248                          which does not implement the `Copy` trait",
249                         note_msg, ty
250                     ));
251                 }
252             }
253
254             if let Some((_, mut old_err)) = self.move_error_reported
255                 .insert(move_out_indices, (used_place.clone(), err))
256             {
257                 // Cancel the old error so it doesn't ICE.
258                 old_err.cancel();
259             }
260         }
261     }
262
263     pub(super) fn report_move_out_while_borrowed(
264         &mut self,
265         location: Location,
266         (place, span): (&Place<'tcx>, Span),
267         borrow: &BorrowData<'tcx>,
268     ) {
269         debug!(
270             "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
271             location, place, span, borrow
272         );
273         let tcx = self.infcx.tcx;
274         let value_msg = match self.describe_place(place) {
275             Some(name) => format!("`{}`", name),
276             None => "value".to_owned(),
277         };
278         let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
279             Some(name) => format!("`{}`", name),
280             None => "value".to_owned(),
281         };
282
283         let borrow_spans = self.retrieve_borrow_spans(borrow);
284         let borrow_span = borrow_spans.args_or_use();
285
286         let move_spans = self.move_spans(place, location);
287         let span = move_spans.args_or_use();
288
289         let mut err = tcx.cannot_move_when_borrowed(
290             span,
291             &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
292             Origin::Mir,
293         );
294         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
295         err.span_label(span, format!("move out of {} occurs here", value_msg));
296
297         borrow_spans.var_span_label(
298             &mut err,
299             format!("borrow occurs due to use{}", borrow_spans.describe())
300         );
301
302         move_spans.var_span_label(
303             &mut err,
304             format!("move occurs due to use{}", move_spans.describe())
305         );
306
307         self.explain_why_borrow_contains_point(
308             location,
309             borrow,
310             None,
311         ).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span));
312         err.buffer(&mut self.errors_buffer);
313     }
314
315     pub(super) fn report_use_while_mutably_borrowed(
316         &mut self,
317         location: Location,
318         (place, _span): (&Place<'tcx>, Span),
319         borrow: &BorrowData<'tcx>,
320     ) -> DiagnosticBuilder<'cx> {
321         let tcx = self.infcx.tcx;
322
323         let borrow_spans = self.retrieve_borrow_spans(borrow);
324         let borrow_span = borrow_spans.args_or_use();
325
326         // Conflicting borrows are reported separately, so only check for move
327         // captures.
328         let use_spans = self.move_spans(place, location);
329         let span = use_spans.var_or_use();
330
331         let mut err = tcx.cannot_use_when_mutably_borrowed(
332             span,
333             &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
334             borrow_span,
335             &self.describe_place(&borrow.borrowed_place)
336                 .unwrap_or_else(|| "_".to_owned()),
337             Origin::Mir,
338         );
339
340         borrow_spans.var_span_label(&mut err, {
341             let place = &borrow.borrowed_place;
342             let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
343
344             format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
345         });
346
347         self.explain_why_borrow_contains_point(location, borrow, None)
348             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
349         err
350     }
351
352     pub(super) fn report_conflicting_borrow(
353         &mut self,
354         location: Location,
355         (place, span): (&Place<'tcx>, Span),
356         gen_borrow_kind: BorrowKind,
357         issued_borrow: &BorrowData<'tcx>,
358     ) -> DiagnosticBuilder<'cx> {
359         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
360         let issued_span = issued_spans.args_or_use();
361
362         let borrow_spans = self.borrow_spans(span, location);
363         let span = borrow_spans.args_or_use();
364
365         let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
366             "generator"
367         } else {
368             "closure"
369         };
370
371         let (desc_place, msg_place, msg_borrow, union_type_name) =
372             self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
373
374         let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
375         let second_borrow_desc = if explanation.is_explained() {
376             "second "
377         } else {
378             ""
379         };
380
381         // FIXME: supply non-"" `opt_via` when appropriate
382         let tcx = self.infcx.tcx;
383         let first_borrow_desc;
384         let mut err = match (
385             gen_borrow_kind,
386             "immutable",
387             "mutable",
388             issued_borrow.kind,
389             "immutable",
390             "mutable",
391         ) {
392             (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
393                 first_borrow_desc = "mutable ";
394                 tcx.cannot_reborrow_already_borrowed(
395                     span,
396                     &desc_place,
397                     &msg_place,
398                     lft,
399                     issued_span,
400                     "it",
401                     rgt,
402                     &msg_borrow,
403                     None,
404                     Origin::Mir,
405                 )
406             }
407             (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
408                 first_borrow_desc = "immutable ";
409                 tcx.cannot_reborrow_already_borrowed(
410                     span,
411                     &desc_place,
412                     &msg_place,
413                     lft,
414                     issued_span,
415                     "it",
416                     rgt,
417                     &msg_borrow,
418                     None,
419                     Origin::Mir,
420                 )
421             }
422
423             (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
424                 first_borrow_desc = "first ";
425                 tcx.cannot_mutably_borrow_multiply(
426                     span,
427                     &desc_place,
428                     &msg_place,
429                     issued_span,
430                     &msg_borrow,
431                     None,
432                     Origin::Mir,
433                 )
434             }
435
436             (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
437                 first_borrow_desc = "first ";
438                 tcx.cannot_uniquely_borrow_by_two_closures(
439                     span,
440                     &desc_place,
441                     issued_span,
442                     None,
443                     Origin::Mir,
444                 )
445             }
446
447             (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
448             | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
449                 let mut err = tcx.cannot_mutate_in_match_guard(
450                     span,
451                     issued_span,
452                     &desc_place,
453                     "mutably borrow",
454                     Origin::Mir,
455                 );
456                 borrow_spans.var_span_label(
457                     &mut err,
458                     format!(
459                         "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()
460                     ),
461                 );
462
463                 return err;
464             }
465
466             (BorrowKind::Unique, _, _, _, _, _) => {
467                 first_borrow_desc = "first ";
468                 tcx.cannot_uniquely_borrow_by_one_closure(
469                     span,
470                     container_name,
471                     &desc_place,
472                     "",
473                     issued_span,
474                     "it",
475                     "",
476                     None,
477                     Origin::Mir,
478                 )
479             },
480
481             (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
482                 first_borrow_desc = "first ";
483                 tcx.cannot_reborrow_already_uniquely_borrowed(
484                     span,
485                     container_name,
486                     &desc_place,
487                     "",
488                     lft,
489                     issued_span,
490                     "",
491                     None,
492                     second_borrow_desc,
493                     Origin::Mir,
494                 )
495             }
496
497             (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
498                 first_borrow_desc = "first ";
499                 tcx.cannot_reborrow_already_uniquely_borrowed(
500                     span,
501                     container_name,
502                     &desc_place,
503                     "",
504                     lft,
505                     issued_span,
506                     "",
507                     None,
508                     second_borrow_desc,
509                     Origin::Mir,
510                 )
511             }
512
513             (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
514             | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
515             | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
516             | (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
517             | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
518             | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
519         };
520
521         if issued_spans == borrow_spans {
522             borrow_spans.var_span_label(
523                 &mut err,
524                 format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()),
525             );
526         } else {
527             let borrow_place = &issued_borrow.borrowed_place;
528             let borrow_place_desc = self.describe_place(borrow_place)
529                                         .unwrap_or_else(|| "_".to_owned());
530             issued_spans.var_span_label(
531                 &mut err,
532                 format!(
533                     "first borrow occurs due to use of `{}`{}",
534                     borrow_place_desc,
535                     issued_spans.describe(),
536                 ),
537             );
538
539             borrow_spans.var_span_label(
540                 &mut err,
541                 format!(
542                     "second borrow occurs due to use of `{}`{}",
543                     desc_place,
544                     borrow_spans.describe(),
545                 ),
546             );
547         }
548
549         if union_type_name != "" {
550             err.note(&format!(
551                 "`{}` is a field of the union `{}`, so it overlaps the field `{}`",
552                 msg_place, union_type_name, msg_borrow,
553             ));
554         }
555
556         explanation.add_explanation_to_diagnostic(
557             self.infcx.tcx,
558             self.mir,
559             &mut err,
560             first_borrow_desc,
561             None,
562         );
563
564         err
565     }
566
567     /// Returns the description of the root place for a conflicting borrow and the full
568     /// descriptions of the places that caused the conflict.
569     ///
570     /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
571     /// attempted while a shared borrow is live, then this function will return:
572     ///
573     ///     ("x", "", "")
574     ///
575     /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
576     /// a shared borrow of another field `x.y`, then this function will return:
577     ///
578     ///     ("x", "x.z", "x.y")
579     ///
580     /// In the more complex union case, where the union is a field of a struct, then if a mutable
581     /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
582     /// another field `x.u.y`, then this function will return:
583     ///
584     ///     ("x.u", "x.u.z", "x.u.y")
585     ///
586     /// This is used when creating error messages like below:
587     ///
588     /// >  cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
589     /// >  mutable (via `a.u.s.b`) [E0502]
590     pub(super) fn describe_place_for_conflicting_borrow(
591         &self,
592         first_borrowed_place: &Place<'tcx>,
593         second_borrowed_place: &Place<'tcx>,
594     ) -> (String, String, String, String) {
595         // Define a small closure that we can use to check if the type of a place
596         // is a union.
597         let is_union = |place: &Place<'tcx>| -> bool {
598             place.ty(self.mir, self.infcx.tcx).ty
599                 .ty_adt_def()
600                 .map(|adt| adt.is_union())
601                 .unwrap_or(false)
602         };
603
604         // Start with an empty tuple, so we can use the functions on `Option` to reduce some
605         // code duplication (particularly around returning an empty description in the failure
606         // case).
607         Some(())
608             .filter(|_| {
609                 // If we have a conflicting borrow of the same place, then we don't want to add
610                 // an extraneous "via x.y" to our diagnostics, so filter out this case.
611                 first_borrowed_place != second_borrowed_place
612             })
613             .and_then(|_| {
614                 // We're going to want to traverse the first borrowed place to see if we can find
615                 // field access to a union. If we find that, then we will keep the place of the
616                 // union being accessed and the field that was being accessed so we can check the
617                 // second borrowed place for the same union and a access to a different field.
618                 let mut current = first_borrowed_place;
619                 while let Place::Projection(box PlaceProjection { base, elem }) = current {
620                     match elem {
621                         ProjectionElem::Field(field, _) if is_union(base) => {
622                             return Some((base, field));
623                         },
624                         _ => current = base,
625                     }
626                 }
627                 None
628             })
629             .and_then(|(target_base, target_field)| {
630                 // With the place of a union and a field access into it, we traverse the second
631                 // borrowed place and look for a access to a different field of the same union.
632                 let mut current = second_borrowed_place;
633                 while let Place::Projection(box PlaceProjection { base, elem }) = current {
634                     match elem {
635                         ProjectionElem::Field(field, _) if {
636                             is_union(base) && field != target_field && base == target_base
637                         } => {
638                             let desc_base = self.describe_place(base)
639                                 .unwrap_or_else(|| "_".to_owned());
640                             let desc_first = self.describe_place(first_borrowed_place)
641                                 .unwrap_or_else(|| "_".to_owned());
642                             let desc_second = self.describe_place(second_borrowed_place)
643                                 .unwrap_or_else(|| "_".to_owned());
644
645                             // Also compute the name of the union type, eg. `Foo` so we
646                             // can add a helpful note with it.
647                             let ty = base.ty(self.mir, self.infcx.tcx).ty;
648
649                             return Some((desc_base, desc_first, desc_second, ty.to_string()));
650                         },
651                         _ => current = base,
652                     }
653                 }
654                 None
655             })
656             .unwrap_or_else(|| {
657                 // If we didn't find a field access into a union, or both places match, then
658                 // only return the description of the first place.
659                 let desc_place = self.describe_place(first_borrowed_place)
660                     .unwrap_or_else(|| "_".to_owned());
661                 (desc_place, "".to_string(), "".to_string(), "".to_string())
662             })
663     }
664
665     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
666     ///
667     /// This means that some data referenced by `borrow` needs to live
668     /// past the point where the StorageDeadOrDrop of `place` occurs.
669     /// This is usually interpreted as meaning that `place` has too
670     /// short a lifetime. (But sometimes it is more useful to report
671     /// it as a more direct conflict between the execution of a
672     /// `Drop::drop` with an aliasing borrow.)
673     pub(super) fn report_borrowed_value_does_not_live_long_enough(
674         &mut self,
675         location: Location,
676         borrow: &BorrowData<'tcx>,
677         place_span: (&Place<'tcx>, Span),
678         kind: Option<WriteKind>,
679     ) {
680         debug!(
681             "report_borrowed_value_does_not_live_long_enough(\
682              {:?}, {:?}, {:?}, {:?}\
683              )",
684             location, borrow, place_span, kind
685         );
686
687         let drop_span = place_span.1;
688         let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id);
689         let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
690             .last()
691             .unwrap();
692
693         let borrow_spans = self.retrieve_borrow_spans(borrow);
694         let borrow_span = borrow_spans.var_or_use();
695
696         let proper_span = match *root_place {
697             Place::Base(PlaceBase::Local(local)) => self.mir.local_decls[local].source_info.span,
698             _ => drop_span,
699         };
700
701         if self.access_place_error_reported
702             .contains(&(root_place.clone(), borrow_span))
703         {
704             debug!(
705                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
706                 borrow_span
707             );
708             return;
709         }
710
711         self.access_place_error_reported
712             .insert((root_place.clone(), borrow_span));
713
714         if let StorageDeadOrDrop::Destructor(dropped_ty) =
715             self.classify_drop_access_kind(&borrow.borrowed_place)
716         {
717             // If a borrow of path `B` conflicts with drop of `D` (and
718             // we're not in the uninteresting case where `B` is a
719             // prefix of `D`), then report this as a more interesting
720             // destructor conflict.
721             if !borrow.borrowed_place.is_prefix_of(place_span.0) {
722                 self.report_borrow_conflicts_with_destructor(
723                     location, borrow, place_span, kind, dropped_ty,
724                 );
725                 return;
726             }
727         }
728
729         let place_desc = self.describe_place(&borrow.borrowed_place);
730
731         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
732         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
733
734         let err = match (place_desc, explanation) {
735             (Some(_), _) if self.is_place_thread_local(root_place) => {
736                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
737             }
738             // If the outlives constraint comes from inside the closure,
739             // for example:
740             //
741             // let x = 0;
742             // let y = &x;
743             // Box::new(|| y) as Box<Fn() -> &'static i32>
744             //
745             // then just use the normal error. The closure isn't escaping
746             // and `move` will not help here.
747             (
748                 Some(ref name),
749                 BorrowExplanation::MustBeValidFor {
750                     category: category @ ConstraintCategory::Return,
751                     from_closure: false,
752                     ref region_name,
753                     span,
754                     ..
755                 },
756             )
757             | (
758                 Some(ref name),
759                 BorrowExplanation::MustBeValidFor {
760                     category: category @ ConstraintCategory::CallArgument,
761                     from_closure: false,
762                     ref region_name,
763                     span,
764                     ..
765                 },
766             ) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
767                 borrow_spans.args_or_use(),
768                 borrow_span,
769                 region_name,
770                 category,
771                 span,
772                 &format!("`{}`", name),
773             ),
774             (
775                 ref name,
776                 BorrowExplanation::MustBeValidFor {
777                     category: ConstraintCategory::Assignment,
778                     from_closure: false,
779                     region_name: RegionName {
780                         source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
781                         ..
782                     },
783                     span,
784                     ..
785                 },
786             ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
787             (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
788                 location,
789                 &name,
790                 &scope_tree,
791                 &borrow,
792                 drop_span,
793                 borrow_spans,
794                 explanation,
795             ),
796             (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
797                 location,
798                 &scope_tree,
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         scope_tree: &'tcx ScopeTree,
815         borrow: &BorrowData<'tcx>,
816         drop_span: Span,
817         borrow_spans: UseSpans,
818         explanation: BorrowExplanation,
819     ) -> DiagnosticBuilder<'cx> {
820         debug!(
821             "report_local_value_does_not_live_long_enough(\
822              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
823              )",
824             location, name, scope_tree, borrow, drop_span, borrow_spans
825         );
826
827         let borrow_span = borrow_spans.var_or_use();
828         if let BorrowExplanation::MustBeValidFor {
829             category,
830             span,
831             ref opt_place_desc,
832             from_closure: false,
833             ..
834         } = explanation {
835             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
836                 borrow,
837                 borrow_span,
838                 span,
839                 category,
840                 opt_place_desc.as_ref(),
841             ) {
842                 return diag;
843             }
844         }
845
846         let mut err = self.infcx.tcx.path_does_not_live_long_enough(
847             borrow_span,
848             &format!("`{}`", name),
849             Origin::Mir,
850         );
851
852         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
853             let region_name = annotation.emit(self, &mut err);
854
855             err.span_label(
856                 borrow_span,
857                 format!("`{}` would have to be valid for `{}`...", name, region_name),
858             );
859
860             if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) {
861                 err.span_label(
862                     drop_span,
863                     format!(
864                         "...but `{}` will be dropped here, when the function `{}` returns",
865                         name,
866                         self.infcx.tcx.hir().name_by_hir_id(fn_hir_id),
867                     ),
868                 );
869
870                 err.note(
871                     "functions cannot return a borrow to data owned within the function's scope, \
872                      functions can only return borrows to data passed as arguments",
873                 );
874                 err.note(
875                     "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
876                      references-and-borrowing.html#dangling-references>",
877                 );
878             } else {
879                 err.span_label(
880                     drop_span,
881                     format!("...but `{}` dropped here while still borrowed", name),
882                 );
883             }
884
885             if let BorrowExplanation::MustBeValidFor { .. } = explanation {
886             } else {
887                 explanation.add_explanation_to_diagnostic(
888                     self.infcx.tcx,
889                     self.mir,
890                     &mut err,
891                     "",
892                     None,
893                 );
894             }
895         } else {
896             err.span_label(borrow_span, "borrowed value does not live long enough");
897             err.span_label(
898                 drop_span,
899                 format!("`{}` dropped here while still borrowed", name),
900             );
901
902             let within = if borrow_spans.for_generator() {
903                 " by generator"
904             } else {
905                 ""
906             };
907
908             borrow_spans.args_span_label(
909                 &mut err,
910                 format!("value captured here{}", within),
911             );
912
913             explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
914         }
915
916         err
917     }
918
919     fn report_borrow_conflicts_with_destructor(
920         &mut self,
921         location: Location,
922         borrow: &BorrowData<'tcx>,
923         (place, drop_span): (&Place<'tcx>, Span),
924         kind: Option<WriteKind>,
925         dropped_ty: Ty<'tcx>,
926     ) {
927         debug!(
928             "report_borrow_conflicts_with_destructor(\
929              {:?}, {:?}, ({:?}, {:?}), {:?}\
930              )",
931             location, borrow, place, drop_span, kind,
932         );
933
934         let borrow_spans = self.retrieve_borrow_spans(borrow);
935         let borrow_span = borrow_spans.var_or_use();
936
937         let mut err = self.infcx
938             .tcx
939             .cannot_borrow_across_destructor(borrow_span, Origin::Mir);
940
941         let what_was_dropped = match self.describe_place(place) {
942             Some(name) => format!("`{}`", name.as_str()),
943             None => String::from("temporary value"),
944         };
945
946         let label = match self.describe_place(&borrow.borrowed_place) {
947             Some(borrowed) => format!(
948                 "here, drop of {D} needs exclusive access to `{B}`, \
949                  because the type `{T}` implements the `Drop` trait",
950                 D = what_was_dropped,
951                 T = dropped_ty,
952                 B = borrowed
953             ),
954             None => format!(
955                 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
956                 D = what_was_dropped,
957                 T = dropped_ty
958             ),
959         };
960         err.span_label(drop_span, label);
961
962         // Only give this note and suggestion if they could be relevant.
963         let explanation =
964             self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
965         match explanation {
966             BorrowExplanation::UsedLater { .. }
967             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
968                 err.note("consider using a `let` binding to create a longer lived value");
969             }
970             _ => {}
971         }
972
973         explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
974
975         err.buffer(&mut self.errors_buffer);
976     }
977
978     fn report_thread_local_value_does_not_live_long_enough(
979         &mut self,
980         drop_span: Span,
981         borrow_span: Span,
982     ) -> DiagnosticBuilder<'cx> {
983         debug!(
984             "report_thread_local_value_does_not_live_long_enough(\
985              {:?}, {:?}\
986              )",
987             drop_span, borrow_span
988         );
989
990         let mut err = self.infcx
991             .tcx
992             .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
993
994         err.span_label(
995             borrow_span,
996             "thread-local variables cannot be borrowed beyond the end of the function",
997         );
998         err.span_label(drop_span, "end of enclosing function is here");
999
1000         err
1001     }
1002
1003     fn report_temporary_value_does_not_live_long_enough(
1004         &mut self,
1005         location: Location,
1006         scope_tree: &'tcx ScopeTree,
1007         borrow: &BorrowData<'tcx>,
1008         drop_span: Span,
1009         borrow_spans: UseSpans,
1010         proper_span: Span,
1011         explanation: BorrowExplanation,
1012     ) -> DiagnosticBuilder<'cx> {
1013         debug!(
1014             "report_temporary_value_does_not_live_long_enough(\
1015              {:?}, {:?}, {:?}, {:?}, {:?}\
1016              )",
1017             location, scope_tree, borrow, drop_span, proper_span
1018         );
1019
1020         if let BorrowExplanation::MustBeValidFor {
1021             category,
1022             span,
1023             from_closure: false,
1024             ..
1025         } = explanation {
1026             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1027                 borrow,
1028                 proper_span,
1029                 span,
1030                 category,
1031                 None,
1032             ) {
1033                 return diag;
1034             }
1035         }
1036
1037         let tcx = self.infcx.tcx;
1038         let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
1039         err.span_label(
1040             proper_span,
1041             "creates a temporary which is freed while still in use",
1042         );
1043         err.span_label(
1044             drop_span,
1045             "temporary value is freed at the end of this statement",
1046         );
1047
1048         match explanation {
1049             BorrowExplanation::UsedLater(..)
1050             | BorrowExplanation::UsedLaterInLoop(..)
1051             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1052                 // Only give this note and suggestion if it could be relevant.
1053                 err.note("consider using a `let` binding to create a longer lived value");
1054             }
1055             _ => {}
1056         }
1057         explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
1058
1059         let within = if borrow_spans.for_generator() {
1060             " by generator"
1061         } else {
1062             ""
1063         };
1064
1065         borrow_spans.args_span_label(
1066             &mut err,
1067             format!("value captured here{}", within),
1068         );
1069
1070         err
1071     }
1072
1073     fn try_report_cannot_return_reference_to_local(
1074         &self,
1075         borrow: &BorrowData<'tcx>,
1076         borrow_span: Span,
1077         return_span: Span,
1078         category: ConstraintCategory,
1079         opt_place_desc: Option<&String>,
1080     ) -> Option<DiagnosticBuilder<'cx>> {
1081         let tcx = self.infcx.tcx;
1082
1083         let return_kind = match category {
1084             ConstraintCategory::Return => "return",
1085             ConstraintCategory::Yield => "yield",
1086             _ => return None,
1087         };
1088
1089         // FIXME use a better heuristic than Spans
1090         let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span {
1091             "reference to"
1092         } else {
1093             "value referencing"
1094         };
1095
1096         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
1097             let local_kind = match borrow.borrowed_place {
1098                 Place::Base(PlaceBase::Local(local)) => {
1099                     match self.mir.local_kind(local) {
1100                         LocalKind::ReturnPointer
1101                         | LocalKind::Temp => bug!("temporary or return pointer with a name"),
1102                         LocalKind::Var => "local variable ",
1103                         LocalKind::Arg
1104                         if !self.upvars.is_empty()
1105                             && local == Local::new(1) => {
1106                             "variable captured by `move` "
1107                         }
1108                         LocalKind::Arg => {
1109                             "function parameter "
1110                         }
1111                     }
1112                 }
1113                 _ => "local data ",
1114             };
1115             (
1116                 format!("{}`{}`", local_kind, place_desc),
1117                 format!("`{}` is borrowed here", place_desc),
1118             )
1119         } else {
1120             let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
1121                 .last()
1122                 .unwrap();
1123             let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
1124                 local
1125             } else {
1126                 bug!("try_report_cannot_return_reference_to_local: not a local")
1127             };
1128             match self.mir.local_kind(local) {
1129                 LocalKind::ReturnPointer | LocalKind::Temp => {
1130                     (
1131                         "temporary value".to_string(),
1132                         "temporary value created here".to_string(),
1133                     )
1134                 }
1135                 LocalKind::Arg => {
1136                     (
1137                         "function parameter".to_string(),
1138                         "function parameter borrowed here".to_string(),
1139                     )
1140                 },
1141                 LocalKind::Var => bug!("local variable without a name"),
1142             }
1143         };
1144
1145         let mut err = tcx.cannot_return_reference_to_local(
1146             return_span,
1147             return_kind,
1148             reference_desc,
1149             &place_desc,
1150             Origin::Mir,
1151         );
1152
1153         if return_span != borrow_span {
1154             err.span_label(borrow_span, note);
1155         }
1156
1157         Some(err)
1158     }
1159
1160     fn report_escaping_closure_capture(
1161         &mut self,
1162         args_span: Span,
1163         var_span: Span,
1164         fr_name: &RegionName,
1165         category: ConstraintCategory,
1166         constraint_span: Span,
1167         captured_var: &str,
1168     ) -> DiagnosticBuilder<'cx> {
1169         let tcx = self.infcx.tcx;
1170
1171         let mut err = tcx.cannot_capture_in_long_lived_closure(
1172             args_span,
1173             captured_var,
1174             var_span,
1175           Origin::Mir,
1176         );
1177
1178         let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
1179             Ok(string) => format!("move {}", string),
1180             Err(_) => "move |<args>| <body>".to_string()
1181         };
1182
1183         err.span_suggestion(
1184             args_span,
1185             &format!("to force the closure to take ownership of {} (and any \
1186                       other referenced variables), use the `move` keyword",
1187                       captured_var),
1188             suggestion,
1189             Applicability::MachineApplicable,
1190         );
1191
1192         match category {
1193             ConstraintCategory::Return => {
1194                 err.span_note(constraint_span, "closure is returned here");
1195             }
1196             ConstraintCategory::CallArgument => {
1197                 fr_name.highlight_region_name(&mut err);
1198                 err.span_note(
1199                     constraint_span,
1200                     &format!("function requires argument type to outlive `{}`", fr_name),
1201                 );
1202             }
1203             _ => bug!("report_escaping_closure_capture called with unexpected constraint \
1204                        category: `{:?}`", category),
1205         }
1206         err
1207     }
1208
1209     fn report_escaping_data(
1210         &mut self,
1211         borrow_span: Span,
1212         name: &Option<String>,
1213         upvar_span: Span,
1214         upvar_name: &str,
1215         escape_span: Span,
1216     ) -> DiagnosticBuilder<'cx> {
1217         let tcx = self.infcx.tcx;
1218
1219         let escapes_from = if tcx.is_closure(self.mir_def_id) {
1220             let tables = tcx.typeck_tables_of(self.mir_def_id);
1221             let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index);
1222             match tables.node_type(mir_hir_id).sty {
1223                 ty::Closure(..) => "closure",
1224                 ty::Generator(..) => "generator",
1225                 _ => bug!("Closure body doesn't have a closure or generator type"),
1226             }
1227         } else {
1228             "function"
1229         };
1230
1231         let mut err = tcx.borrowed_data_escapes_closure(escape_span, escapes_from, Origin::Mir);
1232
1233         err.span_label(
1234             upvar_span,
1235             format!(
1236                 "`{}` is declared here, outside of the {} body",
1237                 upvar_name, escapes_from
1238             ),
1239         );
1240
1241         err.span_label(
1242             borrow_span,
1243             format!(
1244                 "borrow is only valid in the {} body",
1245                 escapes_from
1246             ),
1247         );
1248
1249         if let Some(name) = name {
1250             err.span_label(
1251                 escape_span,
1252                 format!("reference to `{}` escapes the {} body here", name, escapes_from),
1253             );
1254         } else {
1255             err.span_label(
1256                 escape_span,
1257                 format!("reference escapes the {} body here", escapes_from),
1258             );
1259         }
1260
1261         err
1262     }
1263
1264     fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
1265         let mir = self.mir;
1266
1267         let mut stack = Vec::new();
1268         stack.extend(mir.predecessor_locations(location).map(|predecessor| {
1269             let is_back_edge = location.dominates(predecessor, &self.dominators);
1270             (predecessor, is_back_edge)
1271         }));
1272
1273         let mut visited = FxHashSet::default();
1274         let mut result = vec![];
1275
1276         'dfs: while let Some((location, is_back_edge)) = stack.pop() {
1277             debug!(
1278                 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
1279                 location, is_back_edge
1280             );
1281
1282             if !visited.insert(location) {
1283                 continue;
1284             }
1285
1286             // check for moves
1287             let stmt_kind = mir[location.block]
1288                 .statements
1289                 .get(location.statement_index)
1290                 .map(|s| &s.kind);
1291             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
1292                 // this analysis only tries to find moves explicitly
1293                 // written by the user, so we ignore the move-outs
1294                 // created by `StorageDead` and at the beginning
1295                 // of a function.
1296             } else {
1297                 // If we are found a use of a.b.c which was in error, then we want to look for
1298                 // moves not only of a.b.c but also a.b and a.
1299                 //
1300                 // Note that the moves data already includes "parent" paths, so we don't have to
1301                 // worry about the other case: that is, if there is a move of a.b.c, it is already
1302                 // marked as a move of a.b and a as well, so we will generate the correct errors
1303                 // there.
1304                 let mut mpis = vec![mpi];
1305                 let move_paths = &self.move_data.move_paths;
1306                 mpis.extend(move_paths[mpi].parents(move_paths));
1307
1308                 for moi in &self.move_data.loc_map[location] {
1309                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
1310                     if mpis.contains(&self.move_data.moves[*moi].path) {
1311                         debug!("report_use_of_moved_or_uninitialized: found");
1312                         result.push(MoveSite {
1313                             moi: *moi,
1314                             traversed_back_edge: is_back_edge,
1315                         });
1316
1317                         // Strictly speaking, we could continue our DFS here. There may be
1318                         // other moves that can reach the point of error. But it is kind of
1319                         // confusing to highlight them.
1320                         //
1321                         // Example:
1322                         //
1323                         // ```
1324                         // let a = vec![];
1325                         // let b = a;
1326                         // let c = a;
1327                         // drop(a); // <-- current point of error
1328                         // ```
1329                         //
1330                         // Because we stop the DFS here, we only highlight `let c = a`,
1331                         // and not `let b = a`. We will of course also report an error at
1332                         // `let c = a` which highlights `let b = a` as the move.
1333                         continue 'dfs;
1334                     }
1335                 }
1336             }
1337
1338             // check for inits
1339             let mut any_match = false;
1340             drop_flag_effects::for_location_inits(
1341                 self.infcx.tcx,
1342                 self.mir,
1343                 self.move_data,
1344                 location,
1345                 |m| {
1346                     if m == mpi {
1347                         any_match = true;
1348                     }
1349                 },
1350             );
1351             if any_match {
1352                 continue 'dfs;
1353             }
1354
1355             stack.extend(mir.predecessor_locations(location).map(|predecessor| {
1356                 let back_edge = location.dominates(predecessor, &self.dominators);
1357                 (predecessor, is_back_edge || back_edge)
1358             }));
1359         }
1360
1361         result
1362     }
1363
1364     pub(super) fn report_illegal_mutation_of_borrowed(
1365         &mut self,
1366         location: Location,
1367         (place, span): (&Place<'tcx>, Span),
1368         loan: &BorrowData<'tcx>,
1369     ) {
1370         let loan_spans = self.retrieve_borrow_spans(loan);
1371         let loan_span = loan_spans.args_or_use();
1372
1373         let tcx = self.infcx.tcx;
1374         if loan.kind == BorrowKind::Shallow {
1375             let mut err = tcx.cannot_mutate_in_match_guard(
1376                 span,
1377                 loan_span,
1378                 &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
1379                 "assign",
1380                 Origin::Mir,
1381             );
1382             loan_spans.var_span_label(
1383                 &mut err,
1384                 format!("borrow occurs due to use{}", loan_spans.describe()),
1385             );
1386
1387             err.buffer(&mut self.errors_buffer);
1388
1389             return;
1390         }
1391
1392         let mut err = tcx.cannot_assign_to_borrowed(
1393             span,
1394             loan_span,
1395             &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
1396             Origin::Mir,
1397         );
1398
1399         loan_spans.var_span_label(
1400             &mut err,
1401             format!("borrow occurs due to use{}", loan_spans.describe()),
1402         );
1403
1404         self.explain_why_borrow_contains_point(location, loan, None)
1405             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
1406
1407         err.buffer(&mut self.errors_buffer);
1408     }
1409
1410     /// Reports an illegal reassignment; for example, an assignment to
1411     /// (part of) a non-`mut` local that occurs potentially after that
1412     /// local has already been initialized. `place` is the path being
1413     /// assigned; `err_place` is a place providing a reason why
1414     /// `place` is not mutable (e.g., the non-`mut` local `x` in an
1415     /// assignment to `x.f`).
1416     pub(super) fn report_illegal_reassignment(
1417         &mut self,
1418         _location: Location,
1419         (place, span): (&Place<'tcx>, Span),
1420         assigned_span: Span,
1421         err_place: &Place<'tcx>,
1422     ) {
1423         let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place {
1424             if let LocalKind::Arg = self.mir.local_kind(local) {
1425                 (true, Some(&self.mir.local_decls[local]))
1426             } else {
1427                 (false, Some(&self.mir.local_decls[local]))
1428             }
1429         } else {
1430             (false, None)
1431         };
1432
1433         // If root local is initialized immediately (everything apart from let
1434         // PATTERN;) then make the error refer to that local, rather than the
1435         // place being assigned later.
1436         let (place_description, assigned_span) = match local_decl {
1437             Some(LocalDecl {
1438                 is_user_variable: Some(ClearCrossCrate::Clear),
1439                 ..
1440             })
1441             | Some(LocalDecl {
1442                 is_user_variable:
1443                     Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1444                         opt_match_place: None,
1445                         ..
1446                     }))),
1447                 ..
1448             })
1449             | Some(LocalDecl {
1450                 is_user_variable: None,
1451                 ..
1452             })
1453             | None => (self.describe_place(place), assigned_span),
1454             Some(decl) => (self.describe_place(err_place), decl.source_info.span),
1455         };
1456
1457         let mut err = self.infcx.tcx.cannot_reassign_immutable(
1458             span,
1459             place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
1460             from_arg,
1461             Origin::Mir,
1462         );
1463         let msg = if from_arg {
1464             "cannot assign to immutable argument"
1465         } else {
1466             "cannot assign twice to immutable variable"
1467         };
1468         if span != assigned_span {
1469             if !from_arg {
1470                 let value_msg = match place_description {
1471                     Some(name) => format!("`{}`", name),
1472                     None => "value".to_owned(),
1473                 };
1474                 err.span_label(assigned_span, format!("first assignment to {}", value_msg));
1475             }
1476         }
1477         if let Some(decl) = local_decl {
1478             if let Some(name) = decl.name {
1479                 if decl.can_be_made_mutable() {
1480                     err.span_suggestion(
1481                         decl.source_info.span,
1482                         "make this binding mutable",
1483                         format!("mut {}", name),
1484                         Applicability::MachineApplicable,
1485                     );
1486                 }
1487             }
1488         }
1489         err.span_label(span, msg);
1490         err.buffer(&mut self.errors_buffer);
1491     }
1492 }
1493
1494 pub(super) struct IncludingDowncast(bool);
1495
1496 /// Which case a StorageDeadOrDrop is for.
1497 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1498 enum StorageDeadOrDrop<'tcx> {
1499     LocalStorageDead,
1500     BoxedStorageDead,
1501     Destructor(Ty<'tcx>),
1502 }
1503
1504 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1505     /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
1506     /// is moved after being invoked.
1507     ///
1508     /// ```text
1509     /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
1510     ///       its environment
1511     ///   --> $DIR/issue-42065.rs:16:29
1512     ///    |
1513     /// LL |         for (key, value) in dict {
1514     ///    |                             ^^^^
1515     /// ```
1516     pub(super) fn add_moved_or_invoked_closure_note(
1517         &self,
1518         location: Location,
1519         place: &Place<'tcx>,
1520         diag: &mut DiagnosticBuilder<'_>,
1521     ) {
1522         debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
1523         let mut target = place.local();
1524         for stmt in &self.mir[location.block].statements[location.statement_index..] {
1525             debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
1526             if let StatementKind::Assign(into, box Rvalue::Use(from)) = &stmt.kind {
1527                 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
1528                 match from {
1529                     Operand::Copy(ref place) |
1530                     Operand::Move(ref place) if target == place.local() =>
1531                         target = into.local(),
1532                     _ => {},
1533                 }
1534             }
1535         }
1536
1537         // Check if we are attempting to call a closure after it has been invoked.
1538         let terminator = self.mir[location.block].terminator();
1539         debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
1540         if let TerminatorKind::Call {
1541             func: Operand::Constant(box Constant {
1542                 literal: ty::Const {
1543                     ty: &ty::TyS { sty: ty::FnDef(id, _), ..  },
1544                     ..
1545                 },
1546                 ..
1547             }),
1548             args,
1549             ..
1550         } = &terminator.kind {
1551             debug!("add_moved_or_invoked_closure_note: id={:?}", id);
1552             if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
1553                 let closure = match args.first() {
1554                     Some(Operand::Copy(ref place)) |
1555                     Some(Operand::Move(ref place)) if target == place.local() =>
1556                         place.local().unwrap(),
1557                     _ => return,
1558                 };
1559
1560                 debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
1561                 if let ty::Closure(did, _) = self.mir.local_decls[closure].ty.sty {
1562                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
1563
1564                     if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
1565                         .closure_kind_origins()
1566                         .get(hir_id)
1567                     {
1568                         diag.span_note(
1569                             *span,
1570                             &format!(
1571                                 "closure cannot be invoked more than once because it moves the \
1572                                  variable `{}` out of its environment",
1573                                 name,
1574                             ),
1575                         );
1576                         return;
1577                     }
1578                 }
1579             }
1580         }
1581
1582         // Check if we are just moving a closure after it has been invoked.
1583         if let Some(target) = target {
1584             if let ty::Closure(did, _) = self.mir.local_decls[target].ty.sty {
1585                 let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
1586
1587                 if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
1588                     .closure_kind_origins()
1589                     .get(hir_id)
1590                 {
1591                     diag.span_note(
1592                         *span,
1593                         &format!(
1594                             "closure cannot be moved more than once as it is not `Copy` due to \
1595                              moving the variable `{}` out of its environment",
1596                              name
1597                         ),
1598                     );
1599                 }
1600             }
1601         }
1602     }
1603
1604     /// End-user visible description of `place` if one can be found. If the
1605     /// place is a temporary for instance, None will be returned.
1606     pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
1607         self.describe_place_with_options(place, IncludingDowncast(false))
1608     }
1609
1610     /// End-user visible description of `place` if one can be found. If the
1611     /// place is a temporary for instance, None will be returned.
1612     /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
1613     /// `Downcast` and `IncludingDowncast` is true
1614     pub(super) fn describe_place_with_options(
1615         &self,
1616         place: &Place<'tcx>,
1617         including_downcast: IncludingDowncast,
1618     ) -> Option<String> {
1619         let mut buf = String::new();
1620         match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
1621             Ok(()) => Some(buf),
1622             Err(()) => None,
1623         }
1624     }
1625
1626     /// Appends end-user visible description of `place` to `buf`.
1627     fn append_place_to_string(
1628         &self,
1629         place: &Place<'tcx>,
1630         buf: &mut String,
1631         mut autoderef: bool,
1632         including_downcast: &IncludingDowncast,
1633     ) -> Result<(), ()> {
1634         match *place {
1635             Place::Base(PlaceBase::Local(local)) => {
1636                 self.append_local_to_string(local, buf)?;
1637             }
1638             Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
1639                 buf.push_str("promoted");
1640             }
1641             Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
1642                 buf.push_str(&self.infcx.tcx.item_name(def_id).to_string());
1643             }
1644             Place::Projection(ref proj) => {
1645                 match proj.elem {
1646                     ProjectionElem::Deref => {
1647                         let upvar_field_projection =
1648                             self.is_upvar_field_projection(place);
1649                         if let Some(field) = upvar_field_projection {
1650                             let var_index = field.index();
1651                             let name = self.upvars[var_index].name.to_string();
1652                             if self.upvars[var_index].by_ref {
1653                                 buf.push_str(&name);
1654                             } else {
1655                                 buf.push_str(&format!("*{}", &name));
1656                             }
1657                         } else {
1658                             if autoderef {
1659                                 self.append_place_to_string(
1660                                     &proj.base,
1661                                     buf,
1662                                     autoderef,
1663                                     &including_downcast,
1664                                 )?;
1665                             } else if let Place::Base(PlaceBase::Local(local)) = proj.base {
1666                                 if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
1667                                     self.mir.local_decls[local].is_user_variable
1668                                 {
1669                                     self.append_place_to_string(
1670                                         &proj.base,
1671                                         buf,
1672                                         autoderef,
1673                                         &including_downcast,
1674                                     )?;
1675                                 } else {
1676                                     buf.push_str(&"*");
1677                                     self.append_place_to_string(
1678                                         &proj.base,
1679                                         buf,
1680                                         autoderef,
1681                                         &including_downcast,
1682                                     )?;
1683                                 }
1684                             } else {
1685                                 buf.push_str(&"*");
1686                                 self.append_place_to_string(
1687                                     &proj.base,
1688                                     buf,
1689                                     autoderef,
1690                                     &including_downcast,
1691                                 )?;
1692                             }
1693                         }
1694                     }
1695                     ProjectionElem::Downcast(..) => {
1696                         self.append_place_to_string(
1697                             &proj.base,
1698                             buf,
1699                             autoderef,
1700                             &including_downcast,
1701                         )?;
1702                         if including_downcast.0 {
1703                             return Err(());
1704                         }
1705                     }
1706                     ProjectionElem::Field(field, _ty) => {
1707                         autoderef = true;
1708
1709                         let upvar_field_projection =
1710                             self.is_upvar_field_projection(place);
1711                         if let Some(field) = upvar_field_projection {
1712                             let var_index = field.index();
1713                             let name = self.upvars[var_index].name.to_string();
1714                             buf.push_str(&name);
1715                         } else {
1716                             let field_name = self.describe_field(&proj.base, field);
1717                             self.append_place_to_string(
1718                                 &proj.base,
1719                                 buf,
1720                                 autoderef,
1721                                 &including_downcast,
1722                             )?;
1723                             buf.push_str(&format!(".{}", field_name));
1724                         }
1725                     }
1726                     ProjectionElem::Index(index) => {
1727                         autoderef = true;
1728
1729                         self.append_place_to_string(
1730                             &proj.base,
1731                             buf,
1732                             autoderef,
1733                             &including_downcast,
1734                         )?;
1735                         buf.push_str("[");
1736                         if self.append_local_to_string(index, buf).is_err() {
1737                             buf.push_str("_");
1738                         }
1739                         buf.push_str("]");
1740                     }
1741                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1742                         autoderef = true;
1743                         // Since it isn't possible to borrow an element on a particular index and
1744                         // then use another while the borrow is held, don't output indices details
1745                         // to avoid confusing the end-user
1746                         self.append_place_to_string(
1747                             &proj.base,
1748                             buf,
1749                             autoderef,
1750                             &including_downcast,
1751                         )?;
1752                         buf.push_str(&"[..]");
1753                     }
1754                 };
1755             }
1756         }
1757
1758         Ok(())
1759     }
1760
1761     /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
1762     /// a name, then `Err` is returned
1763     fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
1764         let local = &self.mir.local_decls[local_index];
1765         match local.name {
1766             Some(name) => {
1767                 buf.push_str(&name.to_string());
1768                 Ok(())
1769             }
1770             None => Err(()),
1771         }
1772     }
1773
1774     /// End-user visible description of the `field`nth field of `base`
1775     fn describe_field(&self, base: &Place<'tcx>, field: Field) -> String {
1776         match *base {
1777             Place::Base(PlaceBase::Local(local)) => {
1778                 let local = &self.mir.local_decls[local];
1779                 self.describe_field_from_ty(&local.ty, field, None)
1780             }
1781             Place::Base(PlaceBase::Static(ref static_)) =>
1782                 self.describe_field_from_ty(&static_.ty, field, None),
1783             Place::Projection(ref proj) => match proj.elem {
1784                 ProjectionElem::Deref => self.describe_field(&proj.base, field),
1785                 ProjectionElem::Downcast(_, variant_index) => {
1786                     let base_ty = base.ty(self.mir, self.infcx.tcx).ty;
1787                     self.describe_field_from_ty(&base_ty, field, Some(variant_index))
1788                 }
1789                 ProjectionElem::Field(_, field_type) => {
1790                     self.describe_field_from_ty(&field_type, field, None)
1791                 }
1792                 ProjectionElem::Index(..)
1793                 | ProjectionElem::ConstantIndex { .. }
1794                 | ProjectionElem::Subslice { .. } => {
1795                     self.describe_field(&proj.base, field)
1796                 }
1797             },
1798         }
1799     }
1800
1801     /// End-user visible description of the `field_index`nth field of `ty`
1802     fn describe_field_from_ty(
1803         &self,
1804         ty: Ty<'_>,
1805         field: Field,
1806         variant_index: Option<VariantIdx>
1807     ) -> String {
1808         if ty.is_box() {
1809             // If the type is a box, the field is described from the boxed type
1810             self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
1811         } else {
1812             match ty.sty {
1813                 ty::Adt(def, _) => {
1814                     let variant = if let Some(idx) = variant_index {
1815                         assert!(def.is_enum());
1816                         &def.variants[idx]
1817                     } else {
1818                         def.non_enum_variant()
1819                     };
1820                     variant.fields[field.index()]
1821                         .ident
1822                         .to_string()
1823                 },
1824                 ty::Tuple(_) => field.index().to_string(),
1825                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
1826                     self.describe_field_from_ty(&ty, field, variant_index)
1827                 }
1828                 ty::Array(ty, _) | ty::Slice(ty) =>
1829                     self.describe_field_from_ty(&ty, field, variant_index),
1830                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
1831                     // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case
1832                     // the closure comes from another crate. But in that case we wouldn't
1833                     // be borrowck'ing it, so we can just unwrap:
1834                     let upvar = self.infcx.tcx.upvars(def_id).unwrap()[field.index()];
1835
1836                     self.infcx.tcx.hir().name_by_hir_id(upvar.var_id()).to_string()
1837                 }
1838                 _ => {
1839                     // Might need a revision when the fields in trait RFC is implemented
1840                     // (https://github.com/rust-lang/rfcs/pull/1546)
1841                     bug!(
1842                         "End-user description not implemented for field access on `{:?}`",
1843                         ty
1844                     );
1845                 }
1846             }
1847         }
1848     }
1849
1850     /// Checks if a place is a thread-local static.
1851     pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
1852         if let Place::Base(
1853             PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })
1854         ) = place {
1855             let attrs = self.infcx.tcx.get_attrs(*def_id);
1856             let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
1857
1858             debug!(
1859                 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
1860                 attrs, is_thread_local
1861             );
1862             is_thread_local
1863         } else {
1864             debug!("is_place_thread_local: no");
1865             false
1866         }
1867     }
1868
1869     fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
1870         let tcx = self.infcx.tcx;
1871         match place {
1872             Place::Base(PlaceBase::Local(_)) |
1873             Place::Base(PlaceBase::Static(_)) => {
1874                 StorageDeadOrDrop::LocalStorageDead
1875             }
1876             Place::Projection(box PlaceProjection { base, elem }) => {
1877                 let base_access = self.classify_drop_access_kind(base);
1878                 match elem {
1879                     ProjectionElem::Deref => match base_access {
1880                         StorageDeadOrDrop::LocalStorageDead
1881                         | StorageDeadOrDrop::BoxedStorageDead => {
1882                             assert!(
1883                                 base.ty(self.mir, tcx).ty.is_box(),
1884                                 "Drop of value behind a reference or raw pointer"
1885                             );
1886                             StorageDeadOrDrop::BoxedStorageDead
1887                         }
1888                         StorageDeadOrDrop::Destructor(_) => base_access,
1889                     },
1890                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
1891                         let base_ty = base.ty(self.mir, tcx).ty;
1892                         match base_ty.sty {
1893                             ty::Adt(def, _) if def.has_dtor(tcx) => {
1894                                 // Report the outermost adt with a destructor
1895                                 match base_access {
1896                                     StorageDeadOrDrop::Destructor(_) => base_access,
1897                                     StorageDeadOrDrop::LocalStorageDead
1898                                     | StorageDeadOrDrop::BoxedStorageDead => {
1899                                         StorageDeadOrDrop::Destructor(base_ty)
1900                                     }
1901                                 }
1902                             }
1903                             _ => base_access,
1904                         }
1905                     }
1906
1907                     ProjectionElem::ConstantIndex { .. }
1908                     | ProjectionElem::Subslice { .. }
1909                     | ProjectionElem::Index(_) => base_access,
1910                 }
1911             }
1912         }
1913     }
1914
1915     /// Annotate argument and return type of function and closure with (synthesized) lifetime for
1916     /// borrow of local value that does not live long enough.
1917     fn annotate_argument_and_return_for_borrow(
1918         &self,
1919         borrow: &BorrowData<'tcx>,
1920     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
1921         // Define a fallback for when we can't match a closure.
1922         let fallback = || {
1923             let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
1924             if is_closure {
1925                 None
1926             } else {
1927                 let ty = self.infcx.tcx.type_of(self.mir_def_id);
1928                 match ty.sty {
1929                     ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
1930                         self.mir_def_id,
1931                         self.infcx.tcx.fn_sig(self.mir_def_id),
1932                     ),
1933                     _ => None,
1934                 }
1935             }
1936         };
1937
1938         // In order to determine whether we need to annotate, we need to check whether the reserve
1939         // place was an assignment into a temporary.
1940         //
1941         // If it was, we check whether or not that temporary is eventually assigned into the return
1942         // place. If it was, we can add annotations about the function's return type and arguments
1943         // and it'll make sense.
1944         let location = borrow.reserve_location;
1945         debug!(
1946             "annotate_argument_and_return_for_borrow: location={:?}",
1947             location
1948         );
1949         if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
1950              = &self.mir[location.block].statements.get(location.statement_index)
1951         {
1952             debug!(
1953                 "annotate_argument_and_return_for_borrow: reservation={:?}",
1954                 reservation
1955             );
1956             // Check that the initial assignment of the reserve location is into a temporary.
1957             let mut target = *match reservation {
1958                 Place::Base(PlaceBase::Local(local))
1959                     if self.mir.local_kind(*local) == LocalKind::Temp => local,
1960                 _ => return None,
1961             };
1962
1963             // Next, look through the rest of the block, checking if we are assigning the
1964             // `target` (that is, the place that contains our borrow) to anything.
1965             let mut annotated_closure = None;
1966             for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1967                 debug!(
1968                     "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
1969                     target, stmt
1970                 );
1971                 if let StatementKind::Assign(
1972                     Place::Base(PlaceBase::Local(assigned_to)),
1973                     box rvalue
1974                 ) = &stmt.kind {
1975                     debug!(
1976                         "annotate_argument_and_return_for_borrow: assigned_to={:?} \
1977                          rvalue={:?}",
1978                         assigned_to, rvalue
1979                     );
1980                     // Check if our `target` was captured by a closure.
1981                     if let Rvalue::Aggregate(
1982                         box AggregateKind::Closure(def_id, substs),
1983                         operands,
1984                     ) = rvalue
1985                     {
1986                         for operand in operands {
1987                             let assigned_from = match operand {
1988                                 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1989                                     assigned_from
1990                                 }
1991                                 _ => continue,
1992                             };
1993                             debug!(
1994                                 "annotate_argument_and_return_for_borrow: assigned_from={:?}",
1995                                 assigned_from
1996                             );
1997
1998                             // Find the local from the operand.
1999                             let assigned_from_local = match assigned_from.local() {
2000                                 Some(local) => local,
2001                                 None => continue,
2002                             };
2003
2004                             if assigned_from_local != target {
2005                                 continue;
2006                             }
2007
2008                             // If a closure captured our `target` and then assigned
2009                             // into a place then we should annotate the closure in
2010                             // case it ends up being assigned into the return place.
2011                             annotated_closure = self.annotate_fn_sig(
2012                                 *def_id,
2013                                 self.infcx.closure_sig(*def_id, *substs),
2014                             );
2015                             debug!(
2016                                 "annotate_argument_and_return_for_borrow: \
2017                                  annotated_closure={:?} assigned_from_local={:?} \
2018                                  assigned_to={:?}",
2019                                 annotated_closure, assigned_from_local, assigned_to
2020                             );
2021
2022                             if *assigned_to == mir::RETURN_PLACE {
2023                                 // If it was assigned directly into the return place, then
2024                                 // return now.
2025                                 return annotated_closure;
2026                             } else {
2027                                 // Otherwise, update the target.
2028                                 target = *assigned_to;
2029                             }
2030                         }
2031
2032                         // If none of our closure's operands matched, then skip to the next
2033                         // statement.
2034                         continue;
2035                     }
2036
2037                     // Otherwise, look at other types of assignment.
2038                     let assigned_from = match rvalue {
2039                         Rvalue::Ref(_, _, assigned_from) => assigned_from,
2040                         Rvalue::Use(operand) => match operand {
2041                             Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2042                                 assigned_from
2043                             }
2044                             _ => continue,
2045                         },
2046                         _ => continue,
2047                     };
2048                     debug!(
2049                         "annotate_argument_and_return_for_borrow: \
2050                          assigned_from={:?}",
2051                         assigned_from,
2052                     );
2053
2054                     // Find the local from the rvalue.
2055                     let assigned_from_local = match assigned_from.local() {
2056                         Some(local) => local,
2057                         None => continue,
2058                     };
2059                     debug!(
2060                         "annotate_argument_and_return_for_borrow: \
2061                          assigned_from_local={:?}",
2062                         assigned_from_local,
2063                     );
2064
2065                     // Check if our local matches the target - if so, we've assigned our
2066                     // borrow to a new place.
2067                     if assigned_from_local != target {
2068                         continue;
2069                     }
2070
2071                     // If we assigned our `target` into a new place, then we should
2072                     // check if it was the return place.
2073                     debug!(
2074                         "annotate_argument_and_return_for_borrow: \
2075                          assigned_from_local={:?} assigned_to={:?}",
2076                         assigned_from_local, assigned_to
2077                     );
2078                     if *assigned_to == mir::RETURN_PLACE {
2079                         // If it was then return the annotated closure if there was one,
2080                         // else, annotate this function.
2081                         return annotated_closure.or_else(fallback);
2082                     }
2083
2084                     // If we didn't assign into the return place, then we just update
2085                     // the target.
2086                     target = *assigned_to;
2087                 }
2088             }
2089
2090             // Check the terminator if we didn't find anything in the statements.
2091             let terminator = &self.mir[location.block].terminator();
2092             debug!(
2093                 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
2094                 target, terminator
2095             );
2096             if let TerminatorKind::Call {
2097                 destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)),
2098                 args,
2099                 ..
2100             } = &terminator.kind
2101             {
2102                 debug!(
2103                     "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
2104                     assigned_to, args
2105                 );
2106                 for operand in args {
2107                     let assigned_from = match operand {
2108                         Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2109                             assigned_from
2110                         }
2111                         _ => continue,
2112                     };
2113                     debug!(
2114                         "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2115                         assigned_from,
2116                     );
2117
2118                     if let Some(assigned_from_local) = assigned_from.local() {
2119                         debug!(
2120                             "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
2121                             assigned_from_local,
2122                         );
2123
2124                         if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
2125                             return annotated_closure.or_else(fallback);
2126                         }
2127                     }
2128                 }
2129             }
2130         }
2131
2132         // If we haven't found an assignment into the return place, then we need not add
2133         // any annotations.
2134         debug!("annotate_argument_and_return_for_borrow: none found");
2135         None
2136     }
2137
2138     /// Annotate the first argument and return type of a function signature if they are
2139     /// references.
2140     fn annotate_fn_sig(
2141         &self,
2142         did: DefId,
2143         sig: ty::PolyFnSig<'tcx>,
2144     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2145         debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
2146         let is_closure = self.infcx.tcx.is_closure(did);
2147         let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(did)?;
2148         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
2149
2150         // We need to work out which arguments to highlight. We do this by looking
2151         // at the return type, where there are three cases:
2152         //
2153         // 1. If there are named arguments, then we should highlight the return type and
2154         //    highlight any of the arguments that are also references with that lifetime.
2155         //    If there are no arguments that have the same lifetime as the return type,
2156         //    then don't highlight anything.
2157         // 2. The return type is a reference with an anonymous lifetime. If this is
2158         //    the case, then we can take advantage of (and teach) the lifetime elision
2159         //    rules.
2160         //
2161         //    We know that an error is being reported. So the arguments and return type
2162         //    must satisfy the elision rules. Therefore, if there is a single argument
2163         //    then that means the return type and first (and only) argument have the same
2164         //    lifetime and the borrow isn't meeting that, we can highlight the argument
2165         //    and return type.
2166         //
2167         //    If there are multiple arguments then the first argument must be self (else
2168         //    it would not satisfy the elision rules), so we can highlight self and the
2169         //    return type.
2170         // 3. The return type is not a reference. In this case, we don't highlight
2171         //    anything.
2172         let return_ty = sig.output();
2173         match return_ty.skip_binder().sty {
2174             ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
2175                 // This is case 1 from above, return type is a named reference so we need to
2176                 // search for relevant arguments.
2177                 let mut arguments = Vec::new();
2178                 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
2179                     if let ty::Ref(argument_region, _, _) = argument.sty {
2180                         if argument_region == return_region {
2181                             // Need to use the `rustc::ty` types to compare against the
2182                             // `return_region`. Then use the `rustc::hir` type to get only
2183                             // the lifetime span.
2184                             if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node {
2185                                 // With access to the lifetime, we can get
2186                                 // the span of it.
2187                                 arguments.push((*argument, lifetime.span));
2188                             } else {
2189                                 bug!("ty type is a ref but hir type is not");
2190                             }
2191                         }
2192                     }
2193                 }
2194
2195                 // We need to have arguments. This shouldn't happen, but it's worth checking.
2196                 if arguments.is_empty() {
2197                     return None;
2198                 }
2199
2200                 // We use a mix of the HIR and the Ty types to get information
2201                 // as the HIR doesn't have full types for closure arguments.
2202                 let return_ty = *sig.output().skip_binder();
2203                 let mut return_span = fn_decl.output.span();
2204                 if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
2205                     if let hir::TyKind::Rptr(lifetime, _) = ty.into_inner().node {
2206                         return_span = lifetime.span;
2207                     }
2208                 }
2209
2210                 Some(AnnotatedBorrowFnSignature::NamedFunction {
2211                     arguments,
2212                     return_ty,
2213                     return_span,
2214                 })
2215             }
2216             ty::Ref(_, _, _) if is_closure => {
2217                 // This is case 2 from above but only for closures, return type is anonymous
2218                 // reference so we select
2219                 // the first argument.
2220                 let argument_span = fn_decl.inputs.first()?.span;
2221                 let argument_ty = sig.inputs().skip_binder().first()?;
2222
2223                 // Closure arguments are wrapped in a tuple, so we need to get the first
2224                 // from that.
2225                 if let ty::Tuple(elems) = argument_ty.sty {
2226                     let argument_ty = elems.first()?.expect_ty();
2227                     if let ty::Ref(_, _, _) = argument_ty.sty {
2228                         return Some(AnnotatedBorrowFnSignature::Closure {
2229                             argument_ty,
2230                             argument_span,
2231                         });
2232                     }
2233                 }
2234
2235                 None
2236             }
2237             ty::Ref(_, _, _) => {
2238                 // This is also case 2 from above but for functions, return type is still an
2239                 // anonymous reference so we select the first argument.
2240                 let argument_span = fn_decl.inputs.first()?.span;
2241                 let argument_ty = sig.inputs().skip_binder().first()?;
2242
2243                 let return_span = fn_decl.output.span();
2244                 let return_ty = *sig.output().skip_binder();
2245
2246                 // We expect the first argument to be a reference.
2247                 match argument_ty.sty {
2248                     ty::Ref(_, _, _) => {}
2249                     _ => return None,
2250                 }
2251
2252                 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
2253                     argument_ty,
2254                     argument_span,
2255                     return_ty,
2256                     return_span,
2257                 })
2258             }
2259             _ => {
2260                 // This is case 3 from above, return type is not a reference so don't highlight
2261                 // anything.
2262                 None
2263             }
2264         }
2265     }
2266 }
2267
2268 #[derive(Debug)]
2269 enum AnnotatedBorrowFnSignature<'tcx> {
2270     NamedFunction {
2271         arguments: Vec<(Ty<'tcx>, Span)>,
2272         return_ty: Ty<'tcx>,
2273         return_span: Span,
2274     },
2275     AnonymousFunction {
2276         argument_ty: Ty<'tcx>,
2277         argument_span: Span,
2278         return_ty: Ty<'tcx>,
2279         return_span: Span,
2280     },
2281     Closure {
2282         argument_ty: Ty<'tcx>,
2283         argument_span: Span,
2284     },
2285 }
2286
2287 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
2288     /// Annotate the provided diagnostic with information about borrow from the fn signature that
2289     /// helps explain.
2290     fn emit(
2291         &self,
2292         cx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
2293         diag: &mut DiagnosticBuilder<'_>,
2294     ) -> String {
2295         match self {
2296             AnnotatedBorrowFnSignature::Closure {
2297                 argument_ty,
2298                 argument_span,
2299             } => {
2300                 diag.span_label(
2301                     *argument_span,
2302                     format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
2303                 );
2304
2305                 cx.get_region_name_for_ty(argument_ty, 0)
2306             }
2307             AnnotatedBorrowFnSignature::AnonymousFunction {
2308                 argument_ty,
2309                 argument_span,
2310                 return_ty,
2311                 return_span,
2312             } => {
2313                 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
2314                 diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
2315
2316                 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
2317                 let types_equal = return_ty_name == argument_ty_name;
2318                 diag.span_label(
2319                     *return_span,
2320                     format!(
2321                         "{}has type `{}`",
2322                         if types_equal { "also " } else { "" },
2323                         return_ty_name,
2324                     ),
2325                 );
2326
2327                 diag.note(
2328                     "argument and return type have the same lifetime due to lifetime elision rules",
2329                 );
2330                 diag.note(
2331                     "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
2332                      lifetime-syntax.html#lifetime-elision>",
2333                 );
2334
2335                 cx.get_region_name_for_ty(return_ty, 0)
2336             }
2337             AnnotatedBorrowFnSignature::NamedFunction {
2338                 arguments,
2339                 return_ty,
2340                 return_span,
2341             } => {
2342                 // Region of return type and arguments checked to be the same earlier.
2343                 let region_name = cx.get_region_name_for_ty(return_ty, 0);
2344                 for (_, argument_span) in arguments {
2345                     diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
2346                 }
2347
2348                 diag.span_label(
2349                     *return_span,
2350                     format!("also has lifetime `{}`", region_name,),
2351                 );
2352
2353                 diag.help(&format!(
2354                     "use data from the highlighted arguments which match the `{}` lifetime of \
2355                      the return type",
2356                     region_name,
2357                 ));
2358
2359                 region_name
2360             }
2361         }
2362     }
2363 }
2364
2365 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2366     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
2367     /// name where required.
2368     fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
2369         let mut s = String::new();
2370         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
2371
2372         // We need to add synthesized lifetimes where appropriate. We do
2373         // this by hooking into the pretty printer and telling it to label the
2374         // lifetimes without names with the value `'0`.
2375         match ty.sty {
2376             ty::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
2377             | ty::Ref(
2378                 ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
2379                 _,
2380                 _,
2381             ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
2382             _ => {}
2383         }
2384
2385         let _ = ty.print(printer);
2386         s
2387     }
2388
2389     /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
2390     /// synthesized lifetime name where required.
2391     fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
2392         let mut s = String::new();
2393         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
2394
2395         let region = match ty.sty {
2396             ty::Ref(region, _, _) => {
2397                 match region {
2398                     ty::RegionKind::ReLateBound(_, br)
2399                     | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
2400                         printer.region_highlight_mode.highlighting_bound_region(*br, counter)
2401                     }
2402                     _ => {}
2403                 }
2404
2405                 region
2406             }
2407             _ => bug!("ty for annotation of borrow region is not a reference"),
2408         };
2409
2410         let _ = region.print(printer);
2411         s
2412     }
2413 }
2414
2415 // The span(s) associated to a use of a place.
2416 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
2417 pub(super) enum UseSpans {
2418     // The access is caused by capturing a variable for a closure.
2419     ClosureUse {
2420         // This is true if the captured variable was from a generator.
2421         is_generator: bool,
2422         // The span of the args of the closure, including the `move` keyword if
2423         // it's present.
2424         args_span: Span,
2425         // The span of the first use of the captured variable inside the closure.
2426         var_span: Span,
2427     },
2428     // This access has a single span associated to it: common case.
2429     OtherUse(Span),
2430 }
2431
2432 impl UseSpans {
2433     pub(super) fn args_or_use(self) -> Span {
2434         match self {
2435             UseSpans::ClosureUse {
2436                 args_span: span, ..
2437             }
2438             | UseSpans::OtherUse(span) => span,
2439         }
2440     }
2441
2442     pub(super) fn var_or_use(self) -> Span {
2443         match self {
2444             UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
2445         }
2446     }
2447
2448     // Add a span label to the arguments of the closure, if it exists.
2449     pub(super) fn args_span_label(
2450         self,
2451         err: &mut DiagnosticBuilder<'_>,
2452         message: impl Into<String>,
2453     ) {
2454         if let UseSpans::ClosureUse { args_span, .. } = self {
2455             err.span_label(args_span, message);
2456         }
2457     }
2458
2459     // Add a span label to the use of the captured variable, if it exists.
2460     pub(super) fn var_span_label(
2461         self,
2462         err: &mut DiagnosticBuilder<'_>,
2463         message: impl Into<String>,
2464     ) {
2465         if let UseSpans::ClosureUse { var_span, .. } = self {
2466             err.span_label(var_span, message);
2467         }
2468     }
2469
2470     /// Returns `false` if this place is not used in a closure.
2471     fn for_closure(&self) -> bool {
2472         match *self {
2473             UseSpans::ClosureUse { is_generator, .. } => !is_generator,
2474             _ => false,
2475         }
2476     }
2477
2478     /// Returns `false` if this place is not used in a generator.
2479     fn for_generator(&self) -> bool {
2480         match *self {
2481             UseSpans::ClosureUse { is_generator, .. } => is_generator,
2482             _ => false,
2483         }
2484     }
2485
2486     /// Describe the span associated with a use of a place.
2487     fn describe(&self) -> String {
2488         match *self {
2489             UseSpans::ClosureUse { is_generator, .. } => if is_generator {
2490                 " in generator".to_string()
2491             } else {
2492                 " in closure".to_string()
2493             },
2494             _ => "".to_string(),
2495         }
2496     }
2497
2498     pub(super) fn or_else<F>(self, if_other: F) -> Self
2499     where
2500         F: FnOnce() -> Self,
2501     {
2502         match self {
2503             closure @ UseSpans::ClosureUse { .. } => closure,
2504             UseSpans::OtherUse(_) => if_other(),
2505         }
2506     }
2507 }
2508
2509 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2510     /// Finds the spans associated to a move or copy of move_place at location.
2511     pub(super) fn move_spans(
2512         &self,
2513         moved_place: &Place<'tcx>, // Could also be an upvar.
2514         location: Location,
2515     ) -> UseSpans {
2516         use self::UseSpans::*;
2517
2518         let stmt = match self.mir[location.block].statements.get(location.statement_index) {
2519             Some(stmt) => stmt,
2520             None => return OtherUse(self.mir.source_info(location).span),
2521         };
2522
2523         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
2524         if let  StatementKind::Assign(
2525             _,
2526             box Rvalue::Aggregate(ref kind, ref places)
2527         ) = stmt.kind {
2528             let (def_id, is_generator) = match kind {
2529                 box AggregateKind::Closure(def_id, _) => (def_id, false),
2530                 box AggregateKind::Generator(def_id, _, _) => (def_id, true),
2531                 _ => return OtherUse(stmt.source_info.span),
2532             };
2533
2534             debug!(
2535                 "move_spans: def_id={:?} is_generator={:?} places={:?}",
2536                 def_id, is_generator, places
2537             );
2538             if let Some((args_span, var_span)) = self.closure_span(*def_id, moved_place, places) {
2539                 return ClosureUse {
2540                     is_generator,
2541                     args_span,
2542                     var_span,
2543                 };
2544             }
2545         }
2546
2547         OtherUse(stmt.source_info.span)
2548     }
2549
2550     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
2551     /// and its usage of the local assigned at `location`.
2552     /// This is done by searching in statements succeeding `location`
2553     /// and originating from `maybe_closure_span`.
2554     pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
2555         use self::UseSpans::*;
2556         debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
2557
2558         let target = match self.mir[location.block]
2559             .statements
2560             .get(location.statement_index)
2561         {
2562             Some(&Statement {
2563                 kind: StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _),
2564                 ..
2565             }) => local,
2566             _ => return OtherUse(use_span),
2567         };
2568
2569         if self.mir.local_kind(target) != LocalKind::Temp {
2570             // operands are always temporaries.
2571             return OtherUse(use_span);
2572         }
2573
2574         for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
2575             if let StatementKind::Assign(
2576                 _, box Rvalue::Aggregate(ref kind, ref places)
2577             ) = stmt.kind {
2578                 let (def_id, is_generator) = match kind {
2579                     box AggregateKind::Closure(def_id, _) => (def_id, false),
2580                     box AggregateKind::Generator(def_id, _, _) => (def_id, true),
2581                     _ => continue,
2582                 };
2583
2584                 debug!(
2585                     "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
2586                     def_id, is_generator, places
2587                 );
2588                 if let Some((args_span, var_span)) = self.closure_span(
2589                     *def_id, &Place::Base(PlaceBase::Local(target)), places
2590                 ) {
2591                     return ClosureUse {
2592                         is_generator,
2593                         args_span,
2594                         var_span,
2595                     };
2596                 } else {
2597                     return OtherUse(use_span);
2598                 }
2599             }
2600
2601             if use_span != stmt.source_info.span {
2602                 break;
2603             }
2604         }
2605
2606         OtherUse(use_span)
2607     }
2608
2609     /// Finds the span of a captured variable within a closure or generator.
2610     fn closure_span(
2611         &self,
2612         def_id: DefId,
2613         target_place: &Place<'tcx>,
2614         places: &Vec<Operand<'tcx>>,
2615     ) -> Option<(Span, Span)> {
2616         debug!(
2617             "closure_span: def_id={:?} target_place={:?} places={:?}",
2618             def_id, target_place, places
2619         );
2620         let hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id)?;
2621         let expr = &self.infcx.tcx.hir().expect_expr_by_hir_id(hir_id).node;
2622         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
2623         if let hir::ExprKind::Closure(
2624             .., args_span, _
2625         ) = expr {
2626             for (v, place) in self.infcx.tcx.upvars(def_id)?.iter().zip(places) {
2627                 match place {
2628                     Operand::Copy(place) |
2629                     Operand::Move(place) if target_place == place => {
2630                         debug!("closure_span: found captured local {:?}", place);
2631                         return Some((*args_span, v.span));
2632                     },
2633                     _ => {}
2634                 }
2635             }
2636
2637         }
2638         None
2639     }
2640
2641     /// Helper to retrieve span(s) of given borrow from the current MIR
2642     /// representation
2643     pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
2644         let span = self.mir.source_info(borrow.reserve_location).span;
2645         self.borrow_spans(span, borrow.reserve_location)
2646     }
2647 }