1 //! Borrow checker diagnostics.
3 use rustc_errors::DiagnosticBuilder;
5 use rustc_hir::def::Namespace;
6 use rustc_hir::def_id::DefId;
7 use rustc_hir::lang_items::LangItemGroup;
8 use rustc_hir::GeneratorKind;
9 use rustc_middle::mir::{
10 AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
11 Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
13 use rustc_middle::ty::print::Print;
14 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
15 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
16 use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
17 use rustc_target::abi::VariantIdx;
19 use super::borrow_set::BorrowData;
20 use super::MirBorrowckCtxt;
23 mod outlives_suggestion;
27 mod bound_region_errors;
31 mod mutability_errors;
34 crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
35 crate use mutability_errors::AccessKind;
36 crate use outlives_suggestion::OutlivesSuggestionBuilder;
37 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
38 crate use region_name::{RegionName, RegionNameSource};
39 use rustc_span::symbol::Ident;
41 pub(super) struct IncludingDowncast(pub(super) bool);
43 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
44 /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
45 /// is moved after being invoked.
48 /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
50 /// --> $DIR/issue-42065.rs:16:29
52 /// LL | for (key, value) in dict {
55 pub(super) fn add_moved_or_invoked_closure_note(
58 place: PlaceRef<'tcx>,
59 diag: &mut DiagnosticBuilder<'_>,
61 debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
62 let mut target = place.local_or_deref_local();
63 for stmt in &self.body[location.block].statements[location.statement_index..] {
64 debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
65 if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
66 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
68 Operand::Copy(ref place) | Operand::Move(ref place)
69 if target == place.local_or_deref_local() =>
71 target = into.local_or_deref_local()
78 // Check if we are attempting to call a closure after it has been invoked.
79 let terminator = self.body[location.block].terminator();
80 debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
81 if let TerminatorKind::Call {
82 func: Operand::Constant(box Constant { literal, .. }),
87 if let ty::FnDef(id, _) = *literal.ty().kind() {
88 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
89 if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
90 let closure = match args.first() {
91 Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place))
92 if target == place.local_or_deref_local() =>
94 place.local_or_deref_local().unwrap()
99 debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
100 if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
101 let did = did.expect_local();
102 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
104 if let Some((span, hir_place)) =
105 self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
110 "closure cannot be invoked more than once because it moves the \
111 variable `{}` out of its environment",
112 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
122 // Check if we are just moving a closure after it has been invoked.
123 if let Some(target) = target {
124 if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
125 let did = did.expect_local();
126 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
128 if let Some((span, hir_place)) =
129 self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
134 "closure cannot be moved more than once as it is not `Copy` due to \
135 moving the variable `{}` out of its environment",
136 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
144 /// End-user visible description of `place` if one can be found.
145 /// If the place is a temporary for instance, `"value"` will be returned.
146 pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
147 match self.describe_place(place_ref) {
149 // Surround descr with `backticks`.
151 descr.insert(0, '`');
155 None => "value".to_string(),
159 /// End-user visible description of `place` if one can be found.
160 /// If the place is a temporary for instance, None will be returned.
161 pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
162 self.describe_place_with_options(place_ref, IncludingDowncast(false))
165 /// End-user visible description of `place` if one can be found. If the
166 /// place is a temporary for instance, None will be returned.
167 /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
168 /// `Downcast` and `IncludingDowncast` is true
169 pub(super) fn describe_place_with_options(
171 place: PlaceRef<'tcx>,
172 including_downcast: IncludingDowncast,
173 ) -> Option<String> {
174 let mut buf = String::new();
175 match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
181 /// Appends end-user visible description of `place` to `buf`.
182 fn append_place_to_string(
184 place: PlaceRef<'tcx>,
187 including_downcast: &IncludingDowncast,
188 ) -> Result<(), ()> {
190 PlaceRef { local, projection: [] } => {
191 self.append_local_to_string(local, buf)?;
193 PlaceRef { local, projection: [ProjectionElem::Deref] }
194 if self.body.local_decls[local].is_ref_for_guard() =>
196 self.append_place_to_string(
197 PlaceRef { local, projection: &[] },
203 PlaceRef { local, projection: [ProjectionElem::Deref] }
204 if self.body.local_decls[local].is_ref_to_static() =>
206 let local_info = &self.body.local_decls[local].local_info;
207 if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
208 buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
213 PlaceRef { local, projection: [proj_base @ .., elem] } => {
215 ProjectionElem::Deref => {
216 let upvar_field_projection = self.is_upvar_field_projection(place);
217 if let Some(field) = upvar_field_projection {
218 let var_index = field.index();
219 let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
220 if self.upvars[var_index].by_ref {
228 // FIXME turn this recursion into iteration
229 self.append_place_to_string(
230 PlaceRef { local, projection: proj_base },
237 self.append_place_to_string(
238 PlaceRef { local, projection: proj_base },
246 ProjectionElem::Downcast(..) => {
247 self.append_place_to_string(
248 PlaceRef { local, projection: proj_base },
253 if including_downcast.0 {
257 ProjectionElem::Field(field, _ty) => {
260 // FIXME(project-rfc_2229#36): print capture precisely here.
261 let upvar_field_projection = self.is_upvar_field_projection(place);
262 if let Some(field) = upvar_field_projection {
263 let var_index = field.index();
264 let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
267 let field_name = self
268 .describe_field(PlaceRef { local, projection: proj_base }, *field);
269 self.append_place_to_string(
270 PlaceRef { local, projection: proj_base },
276 buf.push_str(&field_name);
279 ProjectionElem::Index(index) => {
282 self.append_place_to_string(
283 PlaceRef { local, projection: proj_base },
289 if self.append_local_to_string(*index, buf).is_err() {
294 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
296 // Since it isn't possible to borrow an element on a particular index and
297 // then use another while the borrow is held, don't output indices details
298 // to avoid confusing the end-user
299 self.append_place_to_string(
300 PlaceRef { local, projection: proj_base },
305 buf.push_str("[..]");
314 /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
315 /// a name, or its name was generated by the compiler, then `Err` is returned
316 fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
317 let decl = &self.body.local_decls[local];
318 match self.local_names[local] {
319 Some(name) if !decl.from_compiler_desugaring() => {
320 buf.push_str(&name.as_str());
327 /// End-user visible description of the `field`nth field of `base`
328 fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
329 // FIXME Place2 Make this work iteratively
331 PlaceRef { local, projection: [] } => {
332 let local = &self.body.local_decls[local];
333 self.describe_field_from_ty(&local.ty, field, None)
335 PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
336 ProjectionElem::Deref => {
337 self.describe_field(PlaceRef { local, projection: proj_base }, field)
339 ProjectionElem::Downcast(_, variant_index) => {
340 let base_ty = place.ty(self.body, self.infcx.tcx).ty;
341 self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
343 ProjectionElem::Field(_, field_type) => {
344 self.describe_field_from_ty(&field_type, field, None)
346 ProjectionElem::Index(..)
347 | ProjectionElem::ConstantIndex { .. }
348 | ProjectionElem::Subslice { .. } => {
349 self.describe_field(PlaceRef { local, projection: proj_base }, field)
355 /// End-user visible description of the `field_index`nth field of `ty`
356 fn describe_field_from_ty(
360 variant_index: Option<VariantIdx>,
363 // If the type is a box, the field is described from the boxed type
364 self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
368 let variant = if let Some(idx) = variant_index {
369 assert!(def.is_enum());
372 def.non_enum_variant()
374 variant.fields[field.index()].ident.to_string()
376 ty::Tuple(_) => field.index().to_string(),
377 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
378 self.describe_field_from_ty(&ty, field, variant_index)
380 ty::Array(ty, _) | ty::Slice(ty) => {
381 self.describe_field_from_ty(&ty, field, variant_index)
383 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
384 // We won't be borrowck'ing here if the closure came from another crate,
385 // so it's safe to call `expect_local`.
387 // We know the field exists so it's safe to call operator[] and `unwrap` here.
391 .typeck(def_id.expect_local())
392 .closure_min_captures_flattened(def_id)
395 .get_root_variable();
397 self.infcx.tcx.hir().name(var_id).to_string()
400 // Might need a revision when the fields in trait RFC is implemented
401 // (https://github.com/rust-lang/rfcs/pull/1546)
402 bug!("End-user description not implemented for field access on `{:?}`", ty);
408 /// Add a note that a type does not implement `Copy`
409 pub(super) fn note_type_does_not_implement_copy(
411 err: &mut DiagnosticBuilder<'a>,
417 let message = format!(
418 "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
419 move_prefix, place_desc, ty,
421 if let Some(span) = span {
422 err.span_label(span, message);
428 pub(super) fn borrowed_content_source(
430 deref_base: PlaceRef<'tcx>,
431 ) -> BorrowedContentSource<'tcx> {
432 let tcx = self.infcx.tcx;
434 // Look up the provided place and work out the move path index for it,
435 // we'll use this to check whether it was originally from an overloaded
437 match self.move_data.rev_lookup.find(deref_base) {
438 LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
439 debug!("borrowed_content_source: mpi={:?}", mpi);
441 for i in &self.move_data.init_path_map[mpi] {
442 let init = &self.move_data.inits[*i];
443 debug!("borrowed_content_source: init={:?}", init);
444 // We're only interested in statements that initialized a value, not the
445 // initializations from arguments.
446 let loc = match init.location {
447 InitLocation::Statement(stmt) => stmt,
451 let bbd = &self.body[loc.block];
452 let is_terminator = bbd.statements.len() == loc.statement_index;
454 "borrowed_content_source: loc={:?} is_terminator={:?}",
459 } else if let Some(Terminator {
460 kind: TerminatorKind::Call { ref func, from_hir_call: false, .. },
464 if let Some(source) =
465 BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
472 // Base is a `static` so won't be from an overloaded operator
476 // If we didn't find an overloaded deref or index, then assume it's a
477 // built in deref and check the type of the base.
478 let base_ty = deref_base.ty(self.body, tcx).ty;
479 if base_ty.is_unsafe_ptr() {
480 BorrowedContentSource::DerefRawPointer
481 } else if base_ty.is_mutable_ptr() {
482 BorrowedContentSource::DerefMutableRef
484 BorrowedContentSource::DerefSharedRef
489 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
490 /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
491 /// name where required.
492 pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
493 let mut s = String::new();
494 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
496 // We need to add synthesized lifetimes where appropriate. We do
497 // this by hooking into the pretty printer and telling it to label the
498 // lifetimes without names with the value `'0`.
501 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
502 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
505 ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
509 let _ = ty.print(printer);
513 /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
514 /// synthesized lifetime name where required.
515 pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
516 let mut s = String::new();
517 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
519 let region = match ty.kind() {
520 ty::Ref(region, _, _) => {
522 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
523 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
524 printer.region_highlight_mode.highlighting_bound_region(*br, counter)
531 _ => bug!("ty for annotation of borrow region is not a reference"),
534 let _ = region.print(printer);
539 /// The span(s) associated to a use of a place.
540 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
541 pub(super) enum UseSpans<'tcx> {
542 /// The access is caused by capturing a variable for a closure.
544 /// This is true if the captured variable was from a generator.
545 generator_kind: Option<GeneratorKind>,
546 /// The span of the args of the closure, including the `move` keyword if
549 /// The span of the use resulting in capture kind
550 /// Check `ty::CaptureInfo` for more details
551 capture_kind_span: Span,
552 /// The span of the use resulting in the captured path
553 /// Check `ty::CaptureInfo` for more details
556 /// The access is caused by using a variable as the receiver of a method
557 /// that takes 'self'
559 /// The span of the variable being moved
561 /// The span of the method call on the variable
563 /// The definition span of the method being called
565 kind: FnSelfUseKind<'tcx>,
567 /// This access is caused by a `match` or `if let` pattern.
569 /// This access has a single span associated to it: common case.
573 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
574 pub(super) enum FnSelfUseKind<'tcx> {
575 /// A normal method call of the form `receiver.foo(a, b, c)`
578 implicit_into_iter: bool,
579 /// Whether the self type of the method call has an `.as_ref()` method.
580 /// Used for better diagnostics.
581 is_option_or_result: bool,
583 /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
585 /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
586 Operator { self_arg: Ident },
588 /// The `Span` of the `Target` associated type
589 /// in the `Deref` impl we are using.
591 /// The type `T::Deref` we are dereferencing to
592 deref_target_ty: Ty<'tcx>,
597 pub(super) fn args_or_use(self) -> Span {
599 UseSpans::ClosureUse { args_span: span, .. }
600 | UseSpans::PatUse(span)
601 | UseSpans::OtherUse(span) => span,
602 UseSpans::FnSelfUse {
603 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
605 UseSpans::FnSelfUse { var_span, .. } => var_span,
609 /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
610 pub(super) fn var_or_use_path_span(self) -> Span {
612 UseSpans::ClosureUse { path_span: span, .. }
613 | UseSpans::PatUse(span)
614 | UseSpans::OtherUse(span) => span,
615 UseSpans::FnSelfUse {
616 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
618 UseSpans::FnSelfUse { var_span, .. } => var_span,
622 /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
623 pub(super) fn var_or_use(self) -> Span {
625 UseSpans::ClosureUse { capture_kind_span: span, .. }
626 | UseSpans::PatUse(span)
627 | UseSpans::OtherUse(span) => span,
628 UseSpans::FnSelfUse {
629 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
631 UseSpans::FnSelfUse { var_span, .. } => var_span,
635 pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
637 UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
642 // Add a span label to the arguments of the closure, if it exists.
643 pub(super) fn args_span_label(
645 err: &mut DiagnosticBuilder<'_>,
646 message: impl Into<String>,
648 if let UseSpans::ClosureUse { args_span, .. } = self {
649 err.span_label(args_span, message);
653 // Add a span label to the use of the captured variable, if it exists.
654 // only adds label to the `path_span`
655 pub(super) fn var_span_label_path_only(
657 err: &mut DiagnosticBuilder<'_>,
658 message: impl Into<String>,
660 if let UseSpans::ClosureUse { path_span, .. } = self {
661 err.span_label(path_span, message);
665 // Add a span label to the use of the captured variable, if it exists.
666 pub(super) fn var_span_label(
668 err: &mut DiagnosticBuilder<'_>,
669 message: impl Into<String>,
670 kind_desc: impl Into<String>,
672 if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
673 if capture_kind_span == path_span {
674 err.span_label(capture_kind_span, message);
676 let capture_kind_label =
677 format!("capture is {} because of use here", kind_desc.into());
678 let path_label = message;
679 err.span_label(capture_kind_span, capture_kind_label);
680 err.span_label(path_span, path_label);
685 /// Returns `false` if this place is not used in a closure.
686 pub(super) fn for_closure(&self) -> bool {
688 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
693 /// Returns `false` if this place is not used in a generator.
694 pub(super) fn for_generator(&self) -> bool {
696 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
701 /// Describe the span associated with a use of a place.
702 pub(super) fn describe(&self) -> String {
704 UseSpans::ClosureUse { generator_kind, .. } => {
705 if generator_kind.is_some() {
706 " in generator".to_string()
708 " in closure".to_string()
715 pub(super) fn or_else<F>(self, if_other: F) -> Self
720 closure @ UseSpans::ClosureUse { .. } => closure,
721 UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
722 fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
727 pub(super) enum BorrowedContentSource<'tcx> {
731 OverloadedDeref(Ty<'tcx>),
732 OverloadedIndex(Ty<'tcx>),
735 impl BorrowedContentSource<'tcx> {
736 pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
738 BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
739 BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
740 BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
741 BorrowedContentSource::OverloadedDeref(ty) => ty
743 .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
744 name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
747 .unwrap_or_else(|| format!("dereference of `{}`", ty)),
748 BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
752 pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
754 BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
755 BorrowedContentSource::DerefSharedRef => Some("shared reference"),
756 BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
757 // Overloaded deref and index operators should be evaluated into a
758 // temporary. So we don't need a description here.
759 BorrowedContentSource::OverloadedDeref(_)
760 | BorrowedContentSource::OverloadedIndex(_) => None,
764 pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
766 BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
767 BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
768 BorrowedContentSource::DerefMutableRef => {
769 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
771 BorrowedContentSource::OverloadedDeref(ty) => ty
773 .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
774 name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
777 .unwrap_or_else(|| format!("dereference of `{}`", ty)),
778 BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
782 fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
784 ty::FnDef(def_id, substs) => {
785 let trait_id = tcx.trait_of_item(def_id)?;
787 let lang_items = tcx.lang_items();
788 if Some(trait_id) == lang_items.deref_trait()
789 || Some(trait_id) == lang_items.deref_mut_trait()
791 Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
792 } else if Some(trait_id) == lang_items.index_trait()
793 || Some(trait_id) == lang_items.index_mut_trait()
795 Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
805 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
806 /// Finds the spans associated to a move or copy of move_place at location.
807 pub(super) fn move_spans(
809 moved_place: PlaceRef<'tcx>, // Could also be an upvar.
811 ) -> UseSpans<'tcx> {
812 use self::UseSpans::*;
814 let stmt = match self.body[location.block].statements.get(location.statement_index) {
816 None => return OtherUse(self.body.source_info(location).span),
819 debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
820 if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
822 box AggregateKind::Closure(def_id, _)
823 | box AggregateKind::Generator(def_id, _, _) => {
824 debug!("move_spans: def_id={:?} places={:?}", def_id, places);
825 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
826 self.closure_span(*def_id, moved_place, places)
840 // StatementKind::FakeRead only contains a def_id if they are introduced as a result
841 // of pattern matching within a closure.
842 if let StatementKind::FakeRead(box (cause, ref place)) = stmt.kind {
844 FakeReadCause::ForMatchedPlace(Some(closure_def_id))
845 | FakeReadCause::ForLet(Some(closure_def_id)) => {
846 debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
847 let places = &[Operand::Move(*place)];
848 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
849 self.closure_span(closure_def_id, moved_place, places)
864 if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
865 PatUse(stmt.source_info.span)
867 OtherUse(stmt.source_info.span)
870 // We are trying to find MIR of the form:
872 // _temp = _moved_val;
874 // FnSelfCall(_temp, ...)
877 // where `_moved_val` is the place we generated the move error for,
878 // `_temp` is some other local, and `FnSelfCall` is a function
879 // that has a `self` parameter.
881 let target_temp = match stmt.kind {
882 StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
883 temp.as_local().unwrap()
885 _ => return normal_ret,
888 debug!("move_spans: target_temp = {:?}", target_temp);
890 if let Some(Terminator {
891 kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
892 }) = &self.body[location.block].terminator
894 let (method_did, method_substs) = if let Some(info) =
895 rustc_const_eval::util::find_self_call(
906 let tcx = self.infcx.tcx;
907 let parent = tcx.parent(method_did);
908 let is_fn_once = parent == tcx.lang_items().fn_once_trait();
909 let is_operator = !from_hir_call
910 && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
911 let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
912 let fn_call_span = *fn_span;
914 let self_arg = tcx.fn_arg_names(method_did)[0];
917 "terminator = {:?} from_hir_call={:?}",
918 self.body[location.block].terminator, from_hir_call
921 // Check for a 'special' use of 'self' -
922 // an FnOnce call, an operator (e.g. `<<`), or a
924 let kind = if is_fn_once {
925 Some(FnSelfUseKind::FnOnceCall)
926 } else if is_operator {
927 Some(FnSelfUseKind::Operator { self_arg })
930 tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
931 Instance::resolve(tcx, self.param_env, deref_target, method_substs)
934 if let Some(Ok(instance)) = deref_target {
935 let deref_target_ty = instance.ty(tcx, self.param_env);
936 Some(FnSelfUseKind::DerefCoercion {
937 deref_target: tcx.def_span(instance.def_id()),
947 let kind = kind.unwrap_or_else(|| {
948 // This isn't a 'special' use of `self`
949 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
950 let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
951 && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
952 let parent_self_ty = parent
953 .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
954 .and_then(|did| match tcx.type_of(did).kind() {
955 ty::Adt(def, ..) => Some(def.did),
958 let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
959 matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
961 FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
965 var_span: stmt.source_info.span,
972 .guess_head_span(self.infcx.tcx.def_span(method_did)),
979 /// Finds the span of arguments of a closure (within `maybe_closure_span`)
980 /// and its usage of the local assigned at `location`.
981 /// This is done by searching in statements succeeding `location`
982 /// and originating from `maybe_closure_span`.
983 pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
984 use self::UseSpans::*;
985 debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
987 let target = match self.body[location.block].statements.get(location.statement_index) {
988 Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => {
989 if let Some(local) = place.as_local() {
992 return OtherUse(use_span);
995 _ => return OtherUse(use_span),
998 if self.body.local_kind(target) != LocalKind::Temp {
999 // operands are always temporaries.
1000 return OtherUse(use_span);
1003 for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
1004 if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) =
1007 let (def_id, is_generator) = match kind {
1008 box AggregateKind::Closure(def_id, _) => (def_id, false),
1009 box AggregateKind::Generator(def_id, _, _) => (def_id, true),
1014 "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
1015 def_id, is_generator, places
1017 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
1018 self.closure_span(*def_id, Place::from(target).as_ref(), places)
1020 return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
1022 return OtherUse(use_span);
1026 if use_span != stmt.source_info.span {
1034 /// Finds the spans of a captured place within a closure or generator.
1035 /// The first span is the location of the use resulting in the capture kind of the capture
1036 /// The second span is the location the use resulting in the captured path of the capture
1040 target_place: PlaceRef<'tcx>,
1041 places: &[Operand<'tcx>],
1042 ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
1044 "closure_span: def_id={:?} target_place={:?} places={:?}",
1045 def_id, target_place, places
1047 let local_did = def_id.as_local()?;
1048 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
1049 let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
1050 debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
1051 if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
1052 for (captured_place, place) in self
1055 .typeck(def_id.expect_local())
1056 .closure_min_captures_flattened(def_id)
1060 Operand::Copy(place) | Operand::Move(place)
1061 if target_place == place.as_ref() =>
1063 debug!("closure_span: found captured local {:?}", place);
1064 let body = self.infcx.tcx.hir().body(*body_id);
1065 let generator_kind = body.generator_kind();
1070 captured_place.get_capture_kind_span(self.infcx.tcx),
1071 captured_place.get_path_span(self.infcx.tcx),
1081 /// Helper to retrieve span(s) of given borrow from the current MIR
1083 pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
1084 let span = self.body.source_info(borrow.reserve_location).span;
1085 self.borrow_spans(span, borrow.reserve_location)