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.
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.
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};
18 use rustc_data_structures::fx::FxHashSet;
19 use rustc_data_structures::sync::Lrc;
20 use rustc_errors::DiagnosticBuilder;
23 use super::borrow_set::BorrowData;
24 use super::{Context, MirBorrowckCtxt};
25 use super::{InitializationRequiringAction, PrefixSet};
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};
33 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
34 pub(super) fn report_use_of_moved_or_uninitialized(
37 desired_action: InitializationRequiringAction,
38 (place, span): (&Place<'tcx>, Span),
42 .move_spans(place, context.loc)
43 .or_else(|| self.borrow_spans(span, context.loc));
44 let span = use_spans.args_or_use();
46 let mois = self.get_moved_indexes(context, mpi);
47 debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
50 let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
52 if self.moved_error_reported.contains(&root_place.clone()) {
54 "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
60 self.moved_error_reported.insert(root_place.clone());
62 let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
63 Some(name) => format!("`{}`", name),
64 None => "value".to_owned(),
66 let mut err = self.tcx.cannot_act_on_uninitialized_variable(
68 desired_action.as_noun(),
70 .describe_place_with_options(place, IncludingDowncast(true))
71 .unwrap_or("_".to_owned()),
74 err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
76 use_spans.var_span_label(
78 format!("{} occurs due to use in closure", desired_action.as_noun()),
81 err.buffer(&mut self.errors_buffer);
83 let msg = ""; //FIXME: add "partially " or "collaterally "
85 let mut err = self.tcx.cannot_act_on_moved_value(
87 desired_action.as_noun(),
89 self.describe_place_with_options(&place, IncludingDowncast(true)),
93 let mut is_loop_move = false;
95 let move_out = self.move_data.moves[*moi];
96 let moved_place = &self.move_data.move_paths[move_out.path].place;
98 let move_spans = self.move_spans(moved_place, move_out.source);
99 let move_span = move_spans.args_or_use();
101 let move_msg = if move_spans.for_closure() {
107 if span == move_span {
110 format!("value moved{} here in previous iteration of loop", move_msg),
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");
119 use_spans.var_span_label(
121 format!("{} occurs due to use in closure", desired_action.as_noun()),
128 "value {} here after move",
129 desired_action.as_verb_in_past_tense()
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() {
150 let mpi = self.move_data.moves[mois[0]].path;
151 let place = &self.move_data.move_paths[mpi].place;
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))
157 Some(name) => format!("`{}`", name),
158 None => "value".to_owned(),
162 "move occurs because {} has type `{}`, \
163 which does not implement the `Copy` trait",
170 err.buffer(&mut self.errors_buffer);
174 pub(super) fn report_move_out_while_borrowed(
177 (place, _span): (&Place<'tcx>, Span),
178 borrow: &BorrowData<'tcx>,
181 let value_msg = match self.describe_place(place) {
182 Some(name) => format!("`{}`", name),
183 None => "value".to_owned(),
185 let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
186 Some(name) => format!("`{}`", name),
187 None => "value".to_owned(),
190 let borrow_spans = self.retrieve_borrow_spans(borrow);
191 let borrow_span = borrow_spans.args_or_use();
193 let move_spans = self.move_spans(place, context.loc);
194 let span = move_spans.args_or_use();
196 let mut err = tcx.cannot_move_when_borrowed(
198 &self.describe_place(place).unwrap_or("_".to_owned()),
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));
204 borrow_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
206 move_spans.var_span_label(&mut err, "move occurs due to use in closure");
208 self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
209 err.buffer(&mut self.errors_buffer);
212 pub(super) fn report_use_while_mutably_borrowed(
215 (place, _span): (&Place<'tcx>, Span),
216 borrow: &BorrowData<'tcx>,
220 let borrow_spans = self.retrieve_borrow_spans(borrow);
221 let borrow_span = borrow_spans.args_or_use();
223 // Conflicting borrows are reported separately, so only check for move
225 let use_spans = self.move_spans(place, context.loc);
226 let span = use_spans.var_or_use();
228 let mut err = tcx.cannot_use_when_mutably_borrowed(
230 &self.describe_place(place).unwrap_or("_".to_owned()),
233 .describe_place(&borrow.borrowed_place)
234 .unwrap_or("_".to_owned()),
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());
242 format!("borrow occurs due to use of `{}` in closure", desc_place)
245 self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
246 err.buffer(&mut self.errors_buffer);
249 pub(super) fn report_conflicting_borrow(
252 (place, span): (&Place<'tcx>, Span),
253 gen_borrow_kind: BorrowKind,
254 issued_borrow: &BorrowData<'tcx>,
256 let issued_spans = self.retrieve_borrow_spans(issued_borrow);
257 let issued_span = issued_spans.args_or_use();
259 let borrow_spans = self.borrow_spans(span, context.loc);
260 let span = borrow_spans.args_or_use();
262 let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
265 // FIXME: supply non-"" `opt_via` when appropriate
266 let mut err = match (
274 (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
275 | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => tcx
276 .cannot_reborrow_already_borrowed(
289 (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => tcx
290 .cannot_mutably_borrow_multiply(
300 (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => tcx
301 .cannot_uniquely_borrow_by_two_closures(
309 (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
320 (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => tcx
321 .cannot_reborrow_already_uniquely_borrowed(
332 (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => tcx
333 .cannot_reborrow_already_uniquely_borrowed(
344 (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
347 if issued_spans == borrow_spans {
348 borrow_spans.var_span_label(
350 format!("borrows occur due to use of `{}` in closure", desc_place),
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(
358 "first borrow occurs due to use of `{}` in closure",
363 borrow_spans.var_span_label(
366 "second borrow occurs due to use of `{}` in closure",
372 self.explain_why_borrow_contains_point(context, issued_borrow, None, &mut err);
374 err.buffer(&mut self.errors_buffer);
377 pub(super) fn report_borrowed_value_does_not_live_long_enough(
380 borrow: &BorrowData<'tcx>,
381 place_span: (&Place<'tcx>, Span),
382 kind: Option<WriteKind>,
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)
391 let borrow_spans = self.retrieve_borrow_spans(borrow);
392 let borrow_span = borrow_spans.var_or_use();
394 let proper_span = match *root_place {
395 Place::Local(local) => self.mir.local_decls[local].source_info.span,
400 .access_place_error_reported
401 .contains(&(root_place.clone(), borrow_span))
404 "suppressing access_place error when borrow doesn't live long enough for {:?}",
410 self.access_place_error_reported
411 .insert((root_place.clone(), borrow_span));
413 let borrow_reason = self.find_why_borrow_contains_point(context, borrow);
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)
419 Some(name) => self.report_local_value_does_not_live_long_enough(
427 kind.map(|k| (k, place_span.0)),
429 None => self.report_temporary_value_does_not_live_long_enough(
439 borrow_spans.args_span_label(&mut err, "value captured here");
441 err.buffer(&mut self.errors_buffer);
444 fn report_local_value_does_not_live_long_enough(
448 scope_tree: &Lrc<ScopeTree>,
449 borrow: &BorrowData<'tcx>,
450 reason: BorrowContainsPointReason<'tcx>,
453 kind_place: Option<(WriteKind, &Place<'tcx>)>,
454 ) -> DiagnosticBuilder<'cx> {
456 "report_local_value_does_not_live_long_enough(\
457 {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
459 context, name, scope_tree, borrow, reason, drop_span, borrow_span
462 let mut err = self.tcx.path_does_not_live_long_enough(
464 &format!("`{}`", name),
468 err.span_label(borrow_span, "borrowed value does not live long enough");
471 format!("`{}` dropped here while still borrowed", name),
474 self.report_why_borrow_contains_point(&mut err, reason, kind_place);
478 fn report_thread_local_value_does_not_live_long_enough(
482 ) -> DiagnosticBuilder<'cx> {
484 "report_thread_local_value_does_not_live_long_enough(\
487 drop_span, borrow_span
492 .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
496 "thread-local variables cannot be borrowed beyond the end of the function",
498 err.span_label(drop_span, "end of enclosing function is here");
502 fn report_temporary_value_does_not_live_long_enough(
505 scope_tree: &Lrc<ScopeTree>,
506 borrow: &BorrowData<'tcx>,
507 reason: BorrowContainsPointReason<'tcx>,
510 ) -> DiagnosticBuilder<'cx> {
512 "report_temporary_value_does_not_live_long_enough(\
513 {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
515 context, scope_tree, borrow, reason, drop_span, proper_span
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");
524 // Only give this note and suggestion if they could be relevant
526 BorrowContainsPointReason::Liveness {..}
527 | BorrowContainsPointReason::DropLiveness {..} => {
528 err.note("consider using a `let` binding to create a longer lived value");
530 BorrowContainsPointReason::OutlivesFreeRegion {..} => (),
533 self.report_why_borrow_contains_point(&mut err, reason, None);
537 fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
540 let mut stack = Vec::new();
541 stack.extend(mir.predecessor_locations(context.loc));
543 let mut visited = FxHashSet();
544 let mut result = vec![];
546 'dfs: while let Some(l) = stack.pop() {
548 "report_use_of_moved_or_uninitialized: current_location={:?}",
552 if !visited.insert(l) {
557 let stmt_kind = mir[l.block]
559 .get(l.statement_index)
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
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");
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.
583 // drop(a); // <-- current point of error
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.
595 let mut any_match = false;
596 drop_flag_effects::for_location_inits(self.tcx, self.mir, self.move_data, l, |m| {
605 stack.extend(mir.predecessor_locations(l));
611 pub(super) fn report_illegal_mutation_of_borrowed(
614 (place, span): (&Place<'tcx>, Span),
615 loan: &BorrowData<'tcx>,
617 let loan_spans = self.retrieve_borrow_spans(loan);
618 let loan_span = loan_spans.args_or_use();
621 let mut err = tcx.cannot_assign_to_borrowed(
624 &self.describe_place(place).unwrap_or("_".to_owned()),
628 loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
630 self.explain_why_borrow_contains_point(context, loan, None, &mut err);
632 err.buffer(&mut self.errors_buffer);
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(
644 (place, span): (&Place<'tcx>, Span),
646 err_place: &Place<'tcx>,
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]))
652 (false, Some(&self.mir.local_decls[local]))
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 {
663 is_user_variable: Some(ClearCrossCrate::Clear),
668 Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
669 opt_match_place: None,
675 is_user_variable: None,
678 | None => (self.describe_place(place), assigned_span),
679 Some(decl) => (self.describe_place(err_place), decl.source_info.span),
682 let mut err = self.tcx.cannot_reassign_immutable(
684 place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
688 let msg = if from_arg {
689 "cannot assign to immutable argument"
691 "cannot assign twice to immutable variable"
693 if span != assigned_span {
695 let value_msg = match place_description {
696 Some(name) => format!("`{}`", name),
697 None => "value".to_owned(),
699 err.span_label(assigned_span, format!("first assignment to {}", value_msg));
702 if let Some(decl) = local_decl {
703 if let Some(name) = decl.name {
704 if decl.can_be_made_mutable() {
706 decl.source_info.span,
707 format!("consider changing this to `mut {}`", name),
712 err.span_label(span, msg);
713 err.buffer(&mut self.errors_buffer);
717 pub(super) struct IncludingDowncast(bool);
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))
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(
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) {
742 // Appends end-user visible description of `place` to `buf`.
743 fn append_place_to_string(
748 including_downcast: &IncludingDowncast,
749 ) -> Result<(), ()> {
751 Place::Promoted(_) => {
752 buf.push_str("promoted");
754 Place::Local(local) => {
755 self.append_local_to_string(local, buf)?;
757 Place::Static(ref static_) => {
758 buf.push_str(&self.tcx.item_name(static_.def_id).to_string());
760 Place::Projection(ref proj) => {
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 {
771 buf.push_str(&format!("*{}", &name));
775 self.append_place_to_string(
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
785 self.append_place_to_string(
793 self.append_place_to_string(
802 self.append_place_to_string(
811 ProjectionElem::Downcast(..) => {
812 self.append_place_to_string(
818 if including_downcast.0 {
822 ProjectionElem::Field(field, _ty) => {
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();
832 let field_name = self.describe_field(&proj.base, field);
833 self.append_place_to_string(
839 buf.push_str(&format!(".{}", field_name));
842 ProjectionElem::Index(index) => {
845 self.append_place_to_string(
852 if self.append_local_to_string(index, buf).is_err() {
857 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
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(
868 buf.push_str(&"[..]");
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];
883 buf.push_str(&name.to_string());
890 // End-user visible description of the `field`nth field of `base`
891 fn describe_field(&self, base: &Place, field: Field) -> String {
893 Place::Local(local) => {
894 let local = &self.mir.local_decls[local];
895 self.describe_field_from_ty(&local.ty, field)
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!(
903 def.variants[variant_index].fields[field.index()].ident
905 ProjectionElem::Field(_, field_type) => {
906 self.describe_field_from_ty(&field_type, field)
908 ProjectionElem::Index(..)
909 | ProjectionElem::ConstantIndex { .. }
910 | ProjectionElem::Subslice { .. } => {
911 self.describe_field(&proj.base, field).to_string()
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 {
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)
924 ty::Adt(def, _) => if def.is_enum() {
925 field.index().to_string()
927 def.non_enum_variant().fields[field.index()]
931 ty::Tuple(_) => field.index().to_string(),
932 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
933 self.describe_field_from_ty(&ty, field)
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()]);
944 self.tcx.hir.name(freevar.var_id()).to_string()
947 // Might need a revision when the fields in trait RFC is implemented
948 // (https://github.com/rust-lang/rfcs/pull/1546)
950 "End-user description not implemented for field access on `{:?}`",
958 // Retrieve type of a place for the current MIR representation
959 fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option<ty::Ty> {
961 Place::Local(local) => {
962 let local = &self.mir.local_decls[*local];
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),
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"));
981 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
982 attrs, is_thread_local
986 debug!("is_place_thread_local: no");
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.
997 // The span of the args of the closure, including the `move` keyword if
1000 // The span of the first use of the captured variable inside the closure.
1003 // This access has a single span associated to it: common case.
1008 pub(super) fn args_or_use(self) -> Span {
1010 UseSpans::ClosureUse {
1013 | UseSpans::OtherUse(span) => span,
1017 pub(super) fn var_or_use(self) -> Span {
1019 UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
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);
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);
1037 pub(super) fn for_closure(self) -> bool {
1039 UseSpans::ClosureUse { .. } => true,
1040 UseSpans::OtherUse(_) => false,
1044 pub(super) fn or_else<F>(self, if_other: F) -> Self
1046 F: FnOnce() -> Self,
1049 closure @ UseSpans::ClosureUse { .. } => closure,
1050 UseSpans::OtherUse(_) => if_other(),
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(
1059 moved_place: &Place<'tcx>, // Could also be an upvar.
1062 use self::UseSpans::*;
1063 use rustc::hir::ExprKind::Closure;
1064 use rustc::mir::AggregateKind;
1066 let stmt = match self.mir[location.block]
1068 .get(location.statement_index)
1071 None => return OtherUse(self.mir.source_info(location).span),
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);
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) {
1083 Operand::Copy(place) | Operand::Move(place)
1084 if moved_place == place =>
1087 "find_closure_move_span: found captured local {:?}",
1090 return Some(v.span);
1107 return OtherUse(stmt.source_info.span);
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;
1119 let local = match self.mir[location.block]
1121 .get(location.statement_index)
1124 kind: StatementKind::Assign(Place::Local(local), _),
1127 _ => return OtherUse(use_span),
1130 if self.mir.local_kind(local) != LocalKind::Temp {
1131 // operands are always temporaries.
1132 return OtherUse(use_span);
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);
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
1146 return OtherUse(use_span);
1150 .with_freevars(node_id, |freevars| {
1151 for (v, place) in freevars.iter().zip(places) {
1153 Operand::Copy(Place::Local(l))
1154 | Operand::Move(Place::Local(l))
1158 "find_closure_borrow_span: found captured local \
1162 return Some(v.span);
1168 }).map(|var_span| ClosureUse {
1171 }).unwrap_or(OtherUse(use_span))
1178 if use_span != stmt.source_info.span {
1186 /// Helper to retrieve span(s) of given borrow from the current MIR
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)