]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/error_reporting.rs
Ignore new test on Windows
[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::WriteKind;
12 use rustc::middle::region::ScopeTree;
13 use rustc::mir::VarBindingForm;
14 use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
15 use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place};
16 use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind};
17 use rustc::ty;
18 use rustc_data_structures::fx::FxHashSet;
19 use rustc_data_structures::sync::Lrc;
20 use rustc_errors::DiagnosticBuilder;
21 use syntax_pos::Span;
22
23 use super::borrow_set::BorrowData;
24 use super::{Context, MirBorrowckCtxt};
25 use super::{InitializationRequiringAction, PrefixSet};
26
27 use borrow_check::nll::explain_borrow::BorrowContainsPointReason;
28 use dataflow::drop_flag_effects;
29 use dataflow::move_paths::indexes::MoveOutIndex;
30 use dataflow::move_paths::MovePathIndex;
31 use util::borrowck_errors::{BorrowckErrors, Origin};
32
33 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
34     pub(super) fn report_use_of_moved_or_uninitialized(
35         &mut self,
36         context: Context,
37         desired_action: InitializationRequiringAction,
38         (place, span): (&Place<'tcx>, Span),
39         mpi: MovePathIndex,
40     ) {
41         let use_spans = self
42             .move_spans(place, context.loc)
43             .or_else(|| self.borrow_spans(span, context.loc));
44         let span = use_spans.args_or_use();
45
46         let mois = self.get_moved_indexes(context, mpi);
47         debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
48
49         if mois.is_empty() {
50             let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
51
52             if self.moved_error_reported.contains(&root_place.clone()) {
53                 debug!(
54                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
55                     root_place
56                 );
57                 return;
58             }
59
60             self.moved_error_reported.insert(root_place.clone());
61
62             let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
63                 Some(name) => format!("`{}`", name),
64                 None => "value".to_owned(),
65             };
66             let mut err = self.tcx.cannot_act_on_uninitialized_variable(
67                 span,
68                 desired_action.as_noun(),
69                 &self
70                     .describe_place_with_options(place, IncludingDowncast(true))
71                     .unwrap_or("_".to_owned()),
72                 Origin::Mir,
73             );
74             err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
75
76             use_spans.var_span_label(
77                 &mut err,
78                 format!("{} occurs due to use in closure", desired_action.as_noun()),
79             );
80
81             err.buffer(&mut self.errors_buffer);
82         } else {
83             let msg = ""; //FIXME: add "partially " or "collaterally "
84
85             let mut err = self.tcx.cannot_act_on_moved_value(
86                 span,
87                 desired_action.as_noun(),
88                 msg,
89                 self.describe_place_with_options(&place, IncludingDowncast(true)),
90                 Origin::Mir,
91             );
92
93             let mut is_loop_move = false;
94             for moi in &mois {
95                 let move_out = self.move_data.moves[*moi];
96                 let moved_place = &self.move_data.move_paths[move_out.path].place;
97
98                 let move_spans = self.move_spans(moved_place, move_out.source);
99                 let move_span = move_spans.args_or_use();
100
101                 let move_msg = if move_spans.for_closure() {
102                     " into closure"
103                 } else {
104                     ""
105                 };
106
107                 if span == move_span {
108                     err.span_label(
109                         span,
110                         format!("value moved{} here in previous iteration of loop", move_msg),
111                     );
112                     is_loop_move = true;
113                 } else {
114                     err.span_label(move_span, format!("value moved{} here", move_msg));
115                     move_spans.var_span_label(&mut err, "variable moved due to use in closure");
116                 };
117             }
118
119             use_spans.var_span_label(
120                 &mut err,
121                 format!("{} occurs due to use in closure", desired_action.as_noun()),
122             );
123
124             if !is_loop_move {
125                 err.span_label(
126                     span,
127                     format!(
128                         "value {} here after move",
129                         desired_action.as_verb_in_past_tense()
130                     ),
131                 );
132             }
133
134             if let Some(ty) = self.retrieve_type_for_place(place) {
135                 let needs_note = match ty.sty {
136                     ty::Closure(id, _) => {
137                         let tables = self.tcx.typeck_tables_of(id);
138                         let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
139                         let hir_id = self.tcx.hir.node_to_hir_id(node_id);
140                         if tables.closure_kind_origins().get(hir_id).is_some() {
141                             false
142                         } else {
143                             true
144                         }
145                     }
146                     _ => true,
147                 };
148
149                 if needs_note {
150                     let mpi = self.move_data.moves[mois[0]].path;
151                     let place = &self.move_data.move_paths[mpi].place;
152
153                     if let Some(ty) = self.retrieve_type_for_place(place) {
154                         let note_msg = match self
155                             .describe_place_with_options(place, IncludingDowncast(true))
156                         {
157                             Some(name) => format!("`{}`", name),
158                             None => "value".to_owned(),
159                         };
160
161                         err.note(&format!(
162                             "move occurs because {} has type `{}`, \
163                              which does not implement the `Copy` trait",
164                             note_msg, ty
165                         ));
166                     }
167                 }
168             }
169
170             err.buffer(&mut self.errors_buffer);
171         }
172     }
173
174     pub(super) fn report_move_out_while_borrowed(
175         &mut self,
176         context: Context,
177         (place, _span): (&Place<'tcx>, Span),
178         borrow: &BorrowData<'tcx>,
179     ) {
180         let tcx = self.tcx;
181         let value_msg = match self.describe_place(place) {
182             Some(name) => format!("`{}`", name),
183             None => "value".to_owned(),
184         };
185         let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
186             Some(name) => format!("`{}`", name),
187             None => "value".to_owned(),
188         };
189
190         let borrow_spans = self.retrieve_borrow_spans(borrow);
191         let borrow_span = borrow_spans.args_or_use();
192
193         let move_spans = self.move_spans(place, context.loc);
194         let span = move_spans.args_or_use();
195
196         let mut err = tcx.cannot_move_when_borrowed(
197             span,
198             &self.describe_place(place).unwrap_or("_".to_owned()),
199             Origin::Mir,
200         );
201         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
202         err.span_label(span, format!("move out of {} occurs here", value_msg));
203
204         borrow_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
205
206         move_spans.var_span_label(&mut err, "move occurs due to use in closure");
207
208         self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
209         err.buffer(&mut self.errors_buffer);
210     }
211
212     pub(super) fn report_use_while_mutably_borrowed(
213         &mut self,
214         context: Context,
215         (place, _span): (&Place<'tcx>, Span),
216         borrow: &BorrowData<'tcx>,
217     ) {
218         let tcx = self.tcx;
219
220         let borrow_spans = self.retrieve_borrow_spans(borrow);
221         let borrow_span = borrow_spans.args_or_use();
222
223         // Conflicting borrows are reported separately, so only check for move
224         // captures.
225         let use_spans = self.move_spans(place, context.loc);
226         let span = use_spans.var_or_use();
227
228         let mut err = tcx.cannot_use_when_mutably_borrowed(
229             span,
230             &self.describe_place(place).unwrap_or("_".to_owned()),
231             borrow_span,
232             &self
233                 .describe_place(&borrow.borrowed_place)
234                 .unwrap_or("_".to_owned()),
235             Origin::Mir,
236         );
237
238         borrow_spans.var_span_label(&mut err, {
239             let place = &borrow.borrowed_place;
240             let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
241
242             format!("borrow occurs due to use of `{}` in closure", desc_place)
243         });
244
245         self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
246         err.buffer(&mut self.errors_buffer);
247     }
248
249     pub(super) fn report_conflicting_borrow(
250         &mut self,
251         context: Context,
252         (place, span): (&Place<'tcx>, Span),
253         gen_borrow_kind: BorrowKind,
254         issued_borrow: &BorrowData<'tcx>,
255     ) {
256         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
257         let issued_span = issued_spans.args_or_use();
258
259         let borrow_spans = self.borrow_spans(span, context.loc);
260         let span = borrow_spans.args_or_use();
261
262         let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
263         let tcx = self.tcx;
264
265         // FIXME: supply non-"" `opt_via` when appropriate
266         let mut err = match (
267             gen_borrow_kind,
268             "immutable",
269             "mutable",
270             issued_borrow.kind,
271             "immutable",
272             "mutable",
273         ) {
274             (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
275             | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
276                 .cannot_reborrow_already_borrowed(
277                     span,
278                     &desc_place,
279                     "",
280                     lft,
281                     issued_span,
282                     "it",
283                     rgt,
284                     "",
285                     None,
286                     Origin::Mir,
287                 ),
288
289             (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
290                 .cannot_mutably_borrow_multiply(
291                     span,
292                     &desc_place,
293                     "",
294                     issued_span,
295                     "",
296                     None,
297                     Origin::Mir,
298                 ),
299
300             (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
301                 .cannot_uniquely_borrow_by_two_closures(
302                     span,
303                     &desc_place,
304                     issued_span,
305                     None,
306                     Origin::Mir,
307                 ),
308
309             (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
310                 span,
311                 &desc_place,
312                 "",
313                 issued_span,
314                 "it",
315                 "",
316                 None,
317                 Origin::Mir,
318             ),
319
320             (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
321                 .cannot_reborrow_already_uniquely_borrowed(
322                     span,
323                     &desc_place,
324                     "",
325                     lft,
326                     issued_span,
327                     "",
328                     None,
329                     Origin::Mir,
330                 ),
331
332             (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
333                 .cannot_reborrow_already_uniquely_borrowed(
334                     span,
335                     &desc_place,
336                     "",
337                     lft,
338                     issued_span,
339                     "",
340                     None,
341                     Origin::Mir,
342                 ),
343
344             (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
345         };
346
347         if issued_spans == borrow_spans {
348             borrow_spans.var_span_label(
349                 &mut err,
350                 format!("borrows occur due to use of `{}` in closure", desc_place),
351             );
352         } else {
353             let borrow_place = &issued_borrow.borrowed_place;
354             let borrow_place_desc = self.describe_place(borrow_place).unwrap_or("_".to_owned());
355             issued_spans.var_span_label(
356                 &mut err,
357                 format!(
358                     "first borrow occurs due to use of `{}` in closure",
359                     borrow_place_desc
360                 ),
361             );
362
363             borrow_spans.var_span_label(
364                 &mut err,
365                 format!(
366                     "second borrow occurs due to use of `{}` in closure",
367                     desc_place
368                 ),
369             );
370         }
371
372         self.explain_why_borrow_contains_point(context, issued_borrow, None, &mut err);
373
374         err.buffer(&mut self.errors_buffer);
375     }
376
377     pub(super) fn report_borrowed_value_does_not_live_long_enough(
378         &mut self,
379         context: Context,
380         borrow: &BorrowData<'tcx>,
381         place_span: (&Place<'tcx>, Span),
382         kind: Option<WriteKind>,
383     ) {
384         let drop_span = place_span.1;
385         let scope_tree = self.tcx.region_scope_tree(self.mir_def_id);
386         let root_place = self
387             .prefixes(&borrow.borrowed_place, PrefixSet::All)
388             .last()
389             .unwrap();
390
391         let borrow_spans = self.retrieve_borrow_spans(borrow);
392         let borrow_span = borrow_spans.var_or_use();
393
394         let proper_span = match *root_place {
395             Place::Local(local) => self.mir.local_decls[local].source_info.span,
396             _ => drop_span,
397         };
398
399         if self
400             .access_place_error_reported
401             .contains(&(root_place.clone(), borrow_span))
402         {
403             debug!(
404                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
405                 borrow_span
406             );
407             return;
408         }
409
410         self.access_place_error_reported
411             .insert((root_place.clone(), borrow_span));
412
413         let borrow_reason = self.find_why_borrow_contains_point(context, borrow);
414
415         let mut err = match &self.describe_place(&borrow.borrowed_place) {
416             Some(_) if self.is_place_thread_local(root_place) => {
417                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
418             }
419             Some(name) => self.report_local_value_does_not_live_long_enough(
420                 context,
421                 name,
422                 &scope_tree,
423                 &borrow,
424                 borrow_reason,
425                 drop_span,
426                 borrow_span,
427                 kind.map(|k| (k, place_span.0)),
428             ),
429             None => self.report_temporary_value_does_not_live_long_enough(
430                 context,
431                 &scope_tree,
432                 &borrow,
433                 borrow_reason,
434                 drop_span,
435                 proper_span,
436             ),
437         };
438
439         borrow_spans.args_span_label(&mut err, "value captured here");
440
441         err.buffer(&mut self.errors_buffer);
442     }
443
444     fn report_local_value_does_not_live_long_enough(
445         &mut self,
446         context: Context,
447         name: &String,
448         scope_tree: &Lrc<ScopeTree>,
449         borrow: &BorrowData<'tcx>,
450         reason: BorrowContainsPointReason<'tcx>,
451         drop_span: Span,
452         borrow_span: Span,
453         kind_place: Option<(WriteKind, &Place<'tcx>)>,
454     ) -> DiagnosticBuilder<'cx> {
455         debug!(
456             "report_local_value_does_not_live_long_enough(\
457              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
458              )",
459             context, name, scope_tree, borrow, reason, drop_span, borrow_span
460         );
461
462         let mut err = self.tcx.path_does_not_live_long_enough(
463             borrow_span,
464             &format!("`{}`", name),
465             Origin::Mir,
466         );
467
468         err.span_label(borrow_span, "borrowed value does not live long enough");
469         err.span_label(
470             drop_span,
471             format!("`{}` dropped here while still borrowed", name),
472         );
473
474         self.report_why_borrow_contains_point(&mut err, reason, kind_place);
475         err
476     }
477
478     fn report_thread_local_value_does_not_live_long_enough(
479         &mut self,
480         drop_span: Span,
481         borrow_span: Span,
482     ) -> DiagnosticBuilder<'cx> {
483         debug!(
484             "report_thread_local_value_does_not_live_long_enough(\
485              {:?}, {:?}\
486              )",
487             drop_span, borrow_span
488         );
489
490         let mut err = self
491             .tcx
492             .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
493
494         err.span_label(
495             borrow_span,
496             "thread-local variables cannot be borrowed beyond the end of the function",
497         );
498         err.span_label(drop_span, "end of enclosing function is here");
499         err
500     }
501
502     fn report_temporary_value_does_not_live_long_enough(
503         &mut self,
504         context: Context,
505         scope_tree: &Lrc<ScopeTree>,
506         borrow: &BorrowData<'tcx>,
507         reason: BorrowContainsPointReason<'tcx>,
508         drop_span: Span,
509         proper_span: Span,
510     ) -> DiagnosticBuilder<'cx> {
511         debug!(
512             "report_temporary_value_does_not_live_long_enough(\
513              {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
514              )",
515             context, scope_tree, borrow, reason, drop_span, proper_span
516         );
517
518         let tcx = self.tcx;
519         let mut err =
520             tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
521         err.span_label(proper_span, "temporary value does not live long enough");
522         err.span_label(drop_span, "temporary value only lives until here");
523
524         // Only give this note and suggestion if they could be relevant
525         match reason {
526             BorrowContainsPointReason::Liveness {..}
527             | BorrowContainsPointReason::DropLiveness {..} => {
528                 err.note("consider using a `let` binding to create a longer lived value");
529             }
530             BorrowContainsPointReason::OutlivesFreeRegion {..} => (),
531         }
532
533         self.report_why_borrow_contains_point(&mut err, reason, None);
534         err
535     }
536
537     fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
538         let mir = self.mir;
539
540         let mut stack = Vec::new();
541         stack.extend(mir.predecessor_locations(context.loc));
542
543         let mut visited = FxHashSet();
544         let mut result = vec![];
545
546         'dfs: while let Some(l) = stack.pop() {
547             debug!(
548                 "report_use_of_moved_or_uninitialized: current_location={:?}",
549                 l
550             );
551
552             if !visited.insert(l) {
553                 continue;
554             }
555
556             // check for moves
557             let stmt_kind = mir[l.block]
558                 .statements
559                 .get(l.statement_index)
560                 .map(|s| &s.kind);
561             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
562                 // this analysis only tries to find moves explicitly
563                 // written by the user, so we ignore the move-outs
564                 // created by `StorageDead` and at the beginning
565                 // of a function.
566             } else {
567                 for moi in &self.move_data.loc_map[l] {
568                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
569                     if self.move_data.moves[*moi].path == mpi {
570                         debug!("report_use_of_moved_or_uninitialized: found");
571                         result.push(*moi);
572
573                         // Strictly speaking, we could continue our DFS here. There may be
574                         // other moves that can reach the point of error. But it is kind of
575                         // confusing to highlight them.
576                         //
577                         // Example:
578                         //
579                         // ```
580                         // let a = vec![];
581                         // let b = a;
582                         // let c = a;
583                         // drop(a); // <-- current point of error
584                         // ```
585                         //
586                         // Because we stop the DFS here, we only highlight `let c = a`,
587                         // and not `let b = a`. We will of course also report an error at
588                         // `let c = a` which highlights `let b = a` as the move.
589                         continue 'dfs;
590                     }
591                 }
592             }
593
594             // check for inits
595             let mut any_match = false;
596             drop_flag_effects::for_location_inits(self.tcx, self.mir, self.move_data, l, |m| {
597                 if m == mpi {
598                     any_match = true;
599                 }
600             });
601             if any_match {
602                 continue 'dfs;
603             }
604
605             stack.extend(mir.predecessor_locations(l));
606         }
607
608         result
609     }
610
611     pub(super) fn report_illegal_mutation_of_borrowed(
612         &mut self,
613         context: Context,
614         (place, span): (&Place<'tcx>, Span),
615         loan: &BorrowData<'tcx>,
616     ) {
617         let loan_spans = self.retrieve_borrow_spans(loan);
618         let loan_span = loan_spans.args_or_use();
619
620         let tcx = self.tcx;
621         let mut err = tcx.cannot_assign_to_borrowed(
622             span,
623             loan_span,
624             &self.describe_place(place).unwrap_or("_".to_owned()),
625             Origin::Mir,
626         );
627
628         loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
629
630         self.explain_why_borrow_contains_point(context, loan, None, &mut err);
631
632         err.buffer(&mut self.errors_buffer);
633     }
634
635     /// Reports an illegal reassignment; for example, an assignment to
636     /// (part of) a non-`mut` local that occurs potentially after that
637     /// local has already been initialized. `place` is the path being
638     /// assigned; `err_place` is a place providing a reason why
639     /// `place` is not mutable (e.g. the non-`mut` local `x` in an
640     /// assignment to `x.f`).
641     pub(super) fn report_illegal_reassignment(
642         &mut self,
643         _context: Context,
644         (place, span): (&Place<'tcx>, Span),
645         assigned_span: Span,
646         err_place: &Place<'tcx>,
647     ) {
648         let (from_arg, local_decl) = if let Place::Local(local) = *err_place {
649             if let LocalKind::Arg = self.mir.local_kind(local) {
650                 (true, Some(&self.mir.local_decls[local]))
651             } else {
652                 (false, Some(&self.mir.local_decls[local]))
653             }
654         } else {
655             (false, None)
656         };
657
658         // If root local is initialized immediately (everything apart from let
659         // PATTERN;) then make the error refer to that local, rather than the
660         // place being assigned later.
661         let (place_description, assigned_span) = match local_decl {
662             Some(LocalDecl {
663                 is_user_variable: Some(ClearCrossCrate::Clear),
664                 ..
665             })
666             | Some(LocalDecl {
667                 is_user_variable:
668                     Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
669                         opt_match_place: None,
670                         ..
671                     }))),
672                 ..
673             })
674             | Some(LocalDecl {
675                 is_user_variable: None,
676                 ..
677             })
678             | None => (self.describe_place(place), assigned_span),
679             Some(decl) => (self.describe_place(err_place), decl.source_info.span),
680         };
681
682         let mut err = self.tcx.cannot_reassign_immutable(
683             span,
684             place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
685             from_arg,
686             Origin::Mir,
687         );
688         let msg = if from_arg {
689             "cannot assign to immutable argument"
690         } else {
691             "cannot assign twice to immutable variable"
692         };
693         if span != assigned_span {
694             if !from_arg {
695                 let value_msg = match place_description {
696                     Some(name) => format!("`{}`", name),
697                     None => "value".to_owned(),
698                 };
699                 err.span_label(assigned_span, format!("first assignment to {}", value_msg));
700             }
701         }
702         if let Some(decl) = local_decl {
703             if let Some(name) = decl.name {
704                 if decl.can_be_made_mutable() {
705                     err.span_label(
706                         decl.source_info.span,
707                         format!("consider changing this to `mut {}`", name),
708                     );
709                 }
710             }
711         }
712         err.span_label(span, msg);
713         err.buffer(&mut self.errors_buffer);
714     }
715 }
716
717 pub(super) struct IncludingDowncast(bool);
718
719 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
720     // End-user visible description of `place` if one can be found. If the
721     // place is a temporary for instance, None will be returned.
722     pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
723         self.describe_place_with_options(place, IncludingDowncast(false))
724     }
725
726     // End-user visible description of `place` if one can be found. If the
727     // place is a temporary for instance, None will be returned.
728     // `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
729     // `Downcast` and `IncludingDowncast` is true
730     pub(super) fn describe_place_with_options(
731         &self,
732         place: &Place<'tcx>,
733         including_downcast: IncludingDowncast,
734     ) -> Option<String> {
735         let mut buf = String::new();
736         match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
737             Ok(()) => Some(buf),
738             Err(()) => None,
739         }
740     }
741
742     // Appends end-user visible description of `place` to `buf`.
743     fn append_place_to_string(
744         &self,
745         place: &Place<'tcx>,
746         buf: &mut String,
747         mut autoderef: bool,
748         including_downcast: &IncludingDowncast,
749     ) -> Result<(), ()> {
750         match *place {
751             Place::Promoted(_) => {
752                 buf.push_str("promoted");
753             }
754             Place::Local(local) => {
755                 self.append_local_to_string(local, buf)?;
756             }
757             Place::Static(ref static_) => {
758                 buf.push_str(&self.tcx.item_name(static_.def_id).to_string());
759             }
760             Place::Projection(ref proj) => {
761                 match proj.elem {
762                     ProjectionElem::Deref => {
763                         let upvar_field_projection =
764                             place.is_upvar_field_projection(self.mir, &self.tcx);
765                         if let Some(field) = upvar_field_projection {
766                             let var_index = field.index();
767                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
768                             if self.mir.upvar_decls[var_index].by_ref {
769                                 buf.push_str(&name);
770                             } else {
771                                 buf.push_str(&format!("*{}", &name));
772                             }
773                         } else {
774                             if autoderef {
775                                 self.append_place_to_string(
776                                     &proj.base,
777                                     buf,
778                                     autoderef,
779                                     &including_downcast,
780                                 )?;
781                             } else if let Place::Local(local) = proj.base {
782                                 if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
783                                     self.mir.local_decls[local].is_user_variable
784                                 {
785                                     self.append_place_to_string(
786                                         &proj.base,
787                                         buf,
788                                         autoderef,
789                                         &including_downcast,
790                                     )?;
791                                 } else {
792                                     buf.push_str(&"*");
793                                     self.append_place_to_string(
794                                         &proj.base,
795                                         buf,
796                                         autoderef,
797                                         &including_downcast,
798                                     )?;
799                                 }
800                             } else {
801                                 buf.push_str(&"*");
802                                 self.append_place_to_string(
803                                     &proj.base,
804                                     buf,
805                                     autoderef,
806                                     &including_downcast,
807                                 )?;
808                             }
809                         }
810                     }
811                     ProjectionElem::Downcast(..) => {
812                         self.append_place_to_string(
813                             &proj.base,
814                             buf,
815                             autoderef,
816                             &including_downcast,
817                         )?;
818                         if including_downcast.0 {
819                             return Err(());
820                         }
821                     }
822                     ProjectionElem::Field(field, _ty) => {
823                         autoderef = true;
824
825                         let upvar_field_projection =
826                             place.is_upvar_field_projection(self.mir, &self.tcx);
827                         if let Some(field) = upvar_field_projection {
828                             let var_index = field.index();
829                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
830                             buf.push_str(&name);
831                         } else {
832                             let field_name = self.describe_field(&proj.base, field);
833                             self.append_place_to_string(
834                                 &proj.base,
835                                 buf,
836                                 autoderef,
837                                 &including_downcast,
838                             )?;
839                             buf.push_str(&format!(".{}", field_name));
840                         }
841                     }
842                     ProjectionElem::Index(index) => {
843                         autoderef = true;
844
845                         self.append_place_to_string(
846                             &proj.base,
847                             buf,
848                             autoderef,
849                             &including_downcast,
850                         )?;
851                         buf.push_str("[");
852                         if self.append_local_to_string(index, buf).is_err() {
853                             buf.push_str("..");
854                         }
855                         buf.push_str("]");
856                     }
857                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
858                         autoderef = true;
859                         // Since it isn't possible to borrow an element on a particular index and
860                         // then use another while the borrow is held, don't output indices details
861                         // to avoid confusing the end-user
862                         self.append_place_to_string(
863                             &proj.base,
864                             buf,
865                             autoderef,
866                             &including_downcast,
867                         )?;
868                         buf.push_str(&"[..]");
869                     }
870                 };
871             }
872         }
873
874         Ok(())
875     }
876
877     // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
878     // a name, then `Err` is returned
879     fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
880         let local = &self.mir.local_decls[local_index];
881         match local.name {
882             Some(name) => {
883                 buf.push_str(&name.to_string());
884                 Ok(())
885             }
886             None => Err(()),
887         }
888     }
889
890     // End-user visible description of the `field`nth field of `base`
891     fn describe_field(&self, base: &Place, field: Field) -> String {
892         match *base {
893             Place::Local(local) => {
894                 let local = &self.mir.local_decls[local];
895                 self.describe_field_from_ty(&local.ty, field)
896             }
897             Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field),
898             Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
899             Place::Projection(ref proj) => match proj.elem {
900                 ProjectionElem::Deref => self.describe_field(&proj.base, field),
901                 ProjectionElem::Downcast(def, variant_index) => format!(
902                     "{}",
903                     def.variants[variant_index].fields[field.index()].ident
904                 ),
905                 ProjectionElem::Field(_, field_type) => {
906                     self.describe_field_from_ty(&field_type, field)
907                 }
908                 ProjectionElem::Index(..)
909                 | ProjectionElem::ConstantIndex { .. }
910                 | ProjectionElem::Subslice { .. } => {
911                     self.describe_field(&proj.base, field).to_string()
912                 }
913             },
914         }
915     }
916
917     // End-user visible description of the `field_index`nth field of `ty`
918     fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
919         if ty.is_box() {
920             // If the type is a box, the field is described from the boxed type
921             self.describe_field_from_ty(&ty.boxed_ty(), field)
922         } else {
923             match ty.sty {
924                 ty::Adt(def, _) => if def.is_enum() {
925                     field.index().to_string()
926                 } else {
927                     def.non_enum_variant().fields[field.index()]
928                         .ident
929                         .to_string()
930                 },
931                 ty::Tuple(_) => field.index().to_string(),
932                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
933                     self.describe_field_from_ty(&ty, field)
934                 }
935                 ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field),
936                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
937                     // Convert the def-id into a node-id. node-ids are only valid for
938                     // the local code in the current crate, so this returns an `Option` in case
939                     // the closure comes from another crate. But in that case we wouldn't
940                     // be borrowck'ing it, so we can just unwrap:
941                     let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
942                     let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
943
944                     self.tcx.hir.name(freevar.var_id()).to_string()
945                 }
946                 _ => {
947                     // Might need a revision when the fields in trait RFC is implemented
948                     // (https://github.com/rust-lang/rfcs/pull/1546)
949                     bug!(
950                         "End-user description not implemented for field access on `{:?}`",
951                         ty.sty
952                     );
953                 }
954             }
955         }
956     }
957
958     // Retrieve type of a place for the current MIR representation
959     fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option<ty::Ty> {
960         match place {
961             Place::Local(local) => {
962                 let local = &self.mir.local_decls[*local];
963                 Some(local.ty)
964             }
965             Place::Promoted(ref prom) => Some(prom.1),
966             Place::Static(ref st) => Some(st.ty),
967             Place::Projection(ref proj) => match proj.elem {
968                 ProjectionElem::Field(_, ty) => Some(ty),
969                 _ => None,
970             },
971         }
972     }
973
974     /// Check if a place is a thread-local static.
975     pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
976         if let Place::Static(statik) = place {
977             let attrs = self.tcx.get_attrs(statik.def_id);
978             let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
979
980             debug!(
981                 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
982                 attrs, is_thread_local
983             );
984             is_thread_local
985         } else {
986             debug!("is_place_thread_local: no");
987             false
988         }
989     }
990 }
991
992 // The span(s) associated to a use of a place.
993 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
994 pub(super) enum UseSpans {
995     // The access is caused by capturing a variable for a closure.
996     ClosureUse {
997         // The span of the args of the closure, including the `move` keyword if
998         // it's present.
999         args_span: Span,
1000         // The span of the first use of the captured variable inside the closure.
1001         var_span: Span,
1002     },
1003     // This access has a single span associated to it: common case.
1004     OtherUse(Span),
1005 }
1006
1007 impl UseSpans {
1008     pub(super) fn args_or_use(self) -> Span {
1009         match self {
1010             UseSpans::ClosureUse {
1011                 args_span: span, ..
1012             }
1013             | UseSpans::OtherUse(span) => span,
1014         }
1015     }
1016
1017     pub(super) fn var_or_use(self) -> Span {
1018         match self {
1019             UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
1020         }
1021     }
1022
1023     // Add a span label to the arguments of the closure, if it exists.
1024     pub(super) fn args_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
1025         if let UseSpans::ClosureUse { args_span, .. } = self {
1026             err.span_label(args_span, message);
1027         }
1028     }
1029
1030     // Add a span label to the use of the captured variable, if it exists.
1031     pub(super) fn var_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
1032         if let UseSpans::ClosureUse { var_span, .. } = self {
1033             err.span_label(var_span, message);
1034         }
1035     }
1036
1037     pub(super) fn for_closure(self) -> bool {
1038         match self {
1039             UseSpans::ClosureUse { .. } => true,
1040             UseSpans::OtherUse(_) => false,
1041         }
1042     }
1043
1044     pub(super) fn or_else<F>(self, if_other: F) -> Self
1045     where
1046         F: FnOnce() -> Self,
1047     {
1048         match self {
1049             closure @ UseSpans::ClosureUse { .. } => closure,
1050             UseSpans::OtherUse(_) => if_other(),
1051         }
1052     }
1053 }
1054
1055 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1056     /// Finds the spans associated to a move or copy of move_place at location.
1057     pub(super) fn move_spans(
1058         &self,
1059         moved_place: &Place<'tcx>, // Could also be an upvar.
1060         location: Location,
1061     ) -> UseSpans {
1062         use self::UseSpans::*;
1063         use rustc::hir::ExprKind::Closure;
1064         use rustc::mir::AggregateKind;
1065
1066         let stmt = match self.mir[location.block]
1067             .statements
1068             .get(location.statement_index)
1069         {
1070             Some(stmt) => stmt,
1071             None => return OtherUse(self.mir.source_info(location).span),
1072         };
1073
1074         if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
1075             if let AggregateKind::Closure(def_id, _) = **kind {
1076                 debug!("find_closure_move_span: found closure {:?}", places);
1077
1078                 if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
1079                     if let Closure(_, _, _, args_span, _) = self.tcx.hir.expect_expr(node_id).node {
1080                         if let Some(var_span) = self.tcx.with_freevars(node_id, |freevars| {
1081                             for (v, place) in freevars.iter().zip(places) {
1082                                 match place {
1083                                     Operand::Copy(place) | Operand::Move(place)
1084                                         if moved_place == place =>
1085                                     {
1086                                         debug!(
1087                                             "find_closure_move_span: found captured local {:?}",
1088                                             place
1089                                         );
1090                                         return Some(v.span);
1091                                     }
1092                                     _ => {}
1093                                 }
1094                             }
1095                             None
1096                         }) {
1097                             return ClosureUse {
1098                                 args_span,
1099                                 var_span,
1100                             };
1101                         }
1102                     }
1103                 }
1104             }
1105         }
1106
1107         return OtherUse(stmt.source_info.span);
1108     }
1109
1110     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
1111     /// and its usage of the local assigned at `location`.
1112     /// This is done by searching in statements succeeding `location`
1113     /// and originating from `maybe_closure_span`.
1114     pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
1115         use self::UseSpans::*;
1116         use rustc::hir::ExprKind::Closure;
1117         use rustc::mir::AggregateKind;
1118
1119         let local = match self.mir[location.block]
1120             .statements
1121             .get(location.statement_index)
1122         {
1123             Some(&Statement {
1124                 kind: StatementKind::Assign(Place::Local(local), _),
1125                 ..
1126             }) => local,
1127             _ => return OtherUse(use_span),
1128         };
1129
1130         if self.mir.local_kind(local) != LocalKind::Temp {
1131             // operands are always temporaries.
1132             return OtherUse(use_span);
1133         }
1134
1135         for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
1136             if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
1137                 if let AggregateKind::Closure(def_id, _) = **kind {
1138                     debug!("find_closure_borrow_span: found closure {:?}", places);
1139
1140                     return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
1141                         let args_span = if let Closure(_, _, _, span, _) =
1142                             self.tcx.hir.expect_expr(node_id).node
1143                         {
1144                             span
1145                         } else {
1146                             return OtherUse(use_span);
1147                         };
1148
1149                         self.tcx
1150                             .with_freevars(node_id, |freevars| {
1151                                 for (v, place) in freevars.iter().zip(places) {
1152                                     match *place {
1153                                         Operand::Copy(Place::Local(l))
1154                                         | Operand::Move(Place::Local(l))
1155                                             if local == l =>
1156                                         {
1157                                             debug!(
1158                                                 "find_closure_borrow_span: found captured local \
1159                                                  {:?}",
1160                                                 l
1161                                             );
1162                                             return Some(v.span);
1163                                         }
1164                                         _ => {}
1165                                     }
1166                                 }
1167                                 None
1168                             }).map(|var_span| ClosureUse {
1169                                 args_span,
1170                                 var_span,
1171                             }).unwrap_or(OtherUse(use_span))
1172                     } else {
1173                         OtherUse(use_span)
1174                     };
1175                 }
1176             }
1177
1178             if use_span != stmt.source_info.span {
1179                 break;
1180             }
1181         }
1182
1183         OtherUse(use_span)
1184     }
1185
1186     /// Helper to retrieve span(s) of given borrow from the current MIR
1187     /// representation
1188     pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData) -> UseSpans {
1189         let span = self.mir.source_info(borrow.reserve_location).span;
1190         self.borrow_spans(span, borrow.reserve_location)
1191     }
1192 }