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