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