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