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
, Field
, Local
, LocalInfo
, LocalKind
, Location
, Operand
, Place
,
11 PlaceRef
, ProjectionElem
, Rvalue
, Statement
, StatementKind
, Terminator
, TerminatorKind
,
13 use rustc_middle
::ty
::print
::Print
;
14 use rustc_middle
::ty
::{self, DefIdTree, Instance, Ty, TyCtxt}
;
16 hygiene
::{DesugaringKind, ForLoopLoc}
,
20 use rustc_target
::abi
::VariantIdx
;
22 use super::borrow_set
::BorrowData
;
23 use super::MirBorrowckCtxt
;
24 use crate::dataflow
::move_paths
::{InitLocation, LookupResult}
;
27 mod outlives_suggestion
;
34 mod mutability_errors
;
37 crate use mutability_errors
::AccessKind
;
38 crate use outlives_suggestion
::OutlivesSuggestionBuilder
;
39 crate use region_errors
::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}
;
40 crate use region_name
::{RegionName, RegionNameSource}
;
41 use rustc_span
::symbol
::Ident
;
43 pub(super) struct IncludingDowncast(pub(super) bool
);
45 impl<'cx
, 'tcx
> MirBorrowckCtxt
<'cx
, 'tcx
> {
46 /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
47 /// is moved after being invoked.
50 /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
52 /// --> $DIR/issue-42065.rs:16:29
54 /// LL | for (key, value) in dict {
57 pub(super) fn add_moved_or_invoked_closure_note(
60 place
: PlaceRef
<'tcx
>,
61 diag
: &mut DiagnosticBuilder
<'_
>,
63 debug
!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location
, place
);
64 let mut target
= place
.local_or_deref_local();
65 for stmt
in &self.body
[location
.block
].statements
[location
.statement_index
..] {
66 debug
!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt
, target
);
67 if let StatementKind
::Assign(box (into
, Rvalue
::Use(from
))) = &stmt
.kind
{
68 debug
!("add_fnonce_closure_note: into={:?} from={:?}", into
, from
);
70 Operand
::Copy(ref place
) | Operand
::Move(ref place
)
71 if target
== place
.local_or_deref_local() =>
73 target
= into
.local_or_deref_local()
80 // Check if we are attempting to call a closure after it has been invoked.
81 let terminator
= self.body
[location
.block
].terminator();
82 debug
!("add_moved_or_invoked_closure_note: terminator={:?}", terminator
);
83 if let TerminatorKind
::Call
{
84 func
: Operand
::Constant(box Constant { literal: ty::Const { ty: const_ty, .. }
, .. }),
89 if let ty
::FnDef(id
, _
) = *const_ty
.kind() {
90 debug
!("add_moved_or_invoked_closure_note: id={:?}", id
);
91 if self.infcx
.tcx
.parent(id
) == self.infcx
.tcx
.lang_items().fn_once_trait() {
92 let closure
= match args
.first() {
93 Some(Operand
::Copy(ref place
)) | Some(Operand
::Move(ref place
))
94 if target
== place
.local_or_deref_local() =>
96 place
.local_or_deref_local().unwrap()
101 debug
!("add_moved_or_invoked_closure_note: closure={:?}", closure
);
102 if let ty
::Closure(did
, _
) = self.body
.local_decls
[closure
].ty
.kind() {
103 let did
= did
.expect_local();
104 let hir_id
= self.infcx
.tcx
.hir().local_def_id_to_hir_id(did
);
106 if let Some((span
, name
)) =
107 self.infcx
.tcx
.typeck(did
).closure_kind_origins().get(hir_id
)
112 "closure cannot be invoked more than once because it moves the \
113 variable `{}` out of its environment",
124 // Check if we are just moving a closure after it has been invoked.
125 if let Some(target
) = target
{
126 if let ty
::Closure(did
, _
) = self.body
.local_decls
[target
].ty
.kind() {
127 let did
= did
.expect_local();
128 let hir_id
= self.infcx
.tcx
.hir().local_def_id_to_hir_id(did
);
130 if let Some((span
, name
)) =
131 self.infcx
.tcx
.typeck(did
).closure_kind_origins().get(hir_id
)
136 "closure cannot be moved more than once as it is not `Copy` due to \
137 moving the variable `{}` out of its environment",
146 /// End-user visible description of `place` if one can be found.
147 /// If the place is a temporary for instance, `"value"` will be returned.
148 pub(super) fn describe_any_place(&self, place_ref
: PlaceRef
<'tcx
>) -> String
{
149 match self.describe_place(place_ref
) {
151 // Surround descr with `backticks`.
153 descr
.insert(0, '`'
);
157 None
=> "value".to_string(),
161 /// End-user visible description of `place` if one can be found.
162 /// If the place is a temporary for instance, None will be returned.
163 pub(super) fn describe_place(&self, place_ref
: PlaceRef
<'tcx
>) -> Option
<String
> {
164 self.describe_place_with_options(place_ref
, IncludingDowncast(false))
167 /// End-user visible description of `place` if one can be found. If the
168 /// place is a temporary for instance, None will be returned.
169 /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
170 /// `Downcast` and `IncludingDowncast` is true
171 pub(super) fn describe_place_with_options(
173 place
: PlaceRef
<'tcx
>,
174 including_downcast
: IncludingDowncast
,
175 ) -> Option
<String
> {
176 let mut buf
= String
::new();
177 match self.append_place_to_string(place
, &mut buf
, false, &including_downcast
) {
183 /// Appends end-user visible description of `place` to `buf`.
184 fn append_place_to_string(
186 place
: PlaceRef
<'tcx
>,
189 including_downcast
: &IncludingDowncast
,
190 ) -> Result
<(), ()> {
192 PlaceRef { local, projection: [] }
=> {
193 self.append_local_to_string(local
, buf
)?
;
195 PlaceRef { local, projection: [ProjectionElem::Deref] }
196 if self.body
.local_decls
[local
].is_ref_for_guard() =>
198 self.append_place_to_string(
199 PlaceRef { local, projection: &[] }
,
205 PlaceRef { local, projection: [ProjectionElem::Deref] }
206 if self.body
.local_decls
[local
].is_ref_to_static() =>
208 let local_info
= &self.body
.local_decls
[local
].local_info
;
209 if let Some(box LocalInfo
::StaticRef { def_id, .. }
) = *local_info
{
210 buf
.push_str(&self.infcx
.tcx
.item_name(def_id
).as_str());
215 PlaceRef { local, projection: [proj_base @ .., elem] }
=> {
217 ProjectionElem
::Deref
=> {
218 let upvar_field_projection
= self.is_upvar_field_projection(place
);
219 if let Some(field
) = upvar_field_projection
{
220 let var_index
= field
.index();
221 let name
= self.upvars
[var_index
].name
.to_string();
222 if self.upvars
[var_index
].by_ref
{
230 // FIXME turn this recursion into iteration
231 self.append_place_to_string(
232 PlaceRef { local, projection: proj_base }
,
239 self.append_place_to_string(
240 PlaceRef { local, projection: proj_base }
,
248 ProjectionElem
::Downcast(..) => {
249 self.append_place_to_string(
250 PlaceRef { local, projection: proj_base }
,
255 if including_downcast
.0 {
259 ProjectionElem
::Field(field
, _ty
) => {
262 let upvar_field_projection
= self.is_upvar_field_projection(place
);
263 if let Some(field
) = upvar_field_projection
{
264 let var_index
= field
.index();
265 let name
= self.upvars
[var_index
].name
.to_string();
268 let field_name
= self
269 .describe_field(PlaceRef { local, projection: proj_base }
, *field
);
270 self.append_place_to_string(
271 PlaceRef { local, projection: proj_base }
,
277 buf
.push_str(&field_name
);
280 ProjectionElem
::Index(index
) => {
283 self.append_place_to_string(
284 PlaceRef { local, projection: proj_base }
,
290 if self.append_local_to_string(*index
, buf
).is_err() {
295 ProjectionElem
::ConstantIndex { .. }
| ProjectionElem
::Subslice { .. }
=> {
297 // Since it isn't possible to borrow an element on a particular index and
298 // then use another while the borrow is held, don't output indices details
299 // to avoid confusing the end-user
300 self.append_place_to_string(
301 PlaceRef { local, projection: proj_base }
,
306 buf
.push_str("[..]");
315 /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
316 /// a name, or its name was generated by the compiler, then `Err` is returned
317 fn append_local_to_string(&self, local
: Local
, buf
: &mut String
) -> Result
<(), ()> {
318 let decl
= &self.body
.local_decls
[local
];
319 match self.local_names
[local
] {
320 Some(name
) if !decl
.from_compiler_desugaring() => {
321 buf
.push_str(&name
.as_str());
328 /// End-user visible description of the `field`nth field of `base`
329 fn describe_field(&self, place
: PlaceRef
<'tcx
>, field
: Field
) -> String
{
330 // FIXME Place2 Make this work iteratively
332 PlaceRef { local, projection: [] }
=> {
333 let local
= &self.body
.local_decls
[local
];
334 self.describe_field_from_ty(&local
.ty
, field
, None
)
336 PlaceRef { local, projection: [proj_base @ .., elem] }
=> match elem
{
337 ProjectionElem
::Deref
=> {
338 self.describe_field(PlaceRef { local, projection: proj_base }
, field
)
340 ProjectionElem
::Downcast(_
, variant_index
) => {
342 Place
::ty_from(place
.local
, place
.projection
, self.body
, self.infcx
.tcx
).ty
;
343 self.describe_field_from_ty(&base_ty
, field
, Some(*variant_index
))
345 ProjectionElem
::Field(_
, field_type
) => {
346 self.describe_field_from_ty(&field_type
, field
, None
)
348 ProjectionElem
::Index(..)
349 | ProjectionElem
::ConstantIndex { .. }
350 | ProjectionElem
::Subslice { .. }
=> {
351 self.describe_field(PlaceRef { local, projection: proj_base }
, field
)
357 /// End-user visible description of the `field_index`nth field of `ty`
358 fn describe_field_from_ty(
362 variant_index
: Option
<VariantIdx
>,
365 // If the type is a box, the field is described from the boxed type
366 self.describe_field_from_ty(&ty
.boxed_ty(), field
, variant_index
)
370 let variant
= if let Some(idx
) = variant_index
{
371 assert
!(def
.is_enum());
374 def
.non_enum_variant()
376 variant
.fields
[field
.index()].ident
.to_string()
378 ty
::Tuple(_
) => field
.index().to_string(),
379 ty
::Ref(_
, ty
, _
) | ty
::RawPtr(ty
::TypeAndMut { ty, .. }
) => {
380 self.describe_field_from_ty(&ty
, field
, variant_index
)
382 ty
::Array(ty
, _
) | ty
::Slice(ty
) => {
383 self.describe_field_from_ty(&ty
, field
, variant_index
)
385 ty
::Closure(def_id
, _
) | ty
::Generator(def_id
, _
, _
) => {
386 // `tcx.upvars_mentioned(def_id)` returns an `Option`, which is `None` in case
387 // the closure comes from another crate. But in that case we wouldn't
388 // be borrowck'ing it, so we can just unwrap:
389 let (&var_id
, _
) = self
392 .upvars_mentioned(def_id
)
394 .get_index(field
.index())
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
= Place
::ty_from(deref_base
.local
, deref_base
.projection
, 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(_
, 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(_
, 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 first use of the captured variable inside the closure.
552 /// The access is caused by using a variable as the receiver of a method
553 /// that takes 'self'
555 /// The span of the variable being moved
557 /// The span of the method call on the variable
559 /// The definition span of the method being called
561 kind
: FnSelfUseKind
<'tcx
>,
563 /// This access is caused by a `match` or `if let` pattern.
565 /// This access has a single span associated to it: common case.
569 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
570 pub(super) enum FnSelfUseKind
<'tcx
> {
571 /// A normal method call of the form `receiver.foo(a, b, c)`
572 Normal { self_arg: Ident, implicit_into_iter: bool }
,
573 /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
575 /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
576 Operator { self_arg: Ident }
,
578 /// The `Span` of the `Target` associated type
579 /// in the `Deref` impl we are using.
581 /// The type `T::Deref` we are dereferencing to
582 deref_target_ty
: Ty
<'tcx
>,
587 pub(super) fn args_or_use(self) -> Span
{
589 UseSpans
::ClosureUse { args_span: span, .. }
590 | UseSpans
::PatUse(span
)
591 | UseSpans
::OtherUse(span
) => span
,
592 UseSpans
::FnSelfUse
{
593 fn_call_span
, kind
: FnSelfUseKind
::DerefCoercion { .. }
, ..
595 UseSpans
::FnSelfUse { var_span, .. }
=> var_span
,
599 pub(super) fn var_or_use(self) -> Span
{
601 UseSpans
::ClosureUse { var_span: span, .. }
602 | UseSpans
::PatUse(span
)
603 | UseSpans
::OtherUse(span
) => span
,
604 UseSpans
::FnSelfUse
{
605 fn_call_span
, kind
: FnSelfUseKind
::DerefCoercion { .. }
, ..
607 UseSpans
::FnSelfUse { var_span, .. }
=> var_span
,
611 pub(super) fn generator_kind(self) -> Option
<GeneratorKind
> {
613 UseSpans
::ClosureUse { generator_kind, .. }
=> generator_kind
,
618 // Add a span label to the arguments of the closure, if it exists.
619 pub(super) fn args_span_label(
621 err
: &mut DiagnosticBuilder
<'_
>,
622 message
: impl Into
<String
>,
624 if let UseSpans
::ClosureUse { args_span, .. }
= self {
625 err
.span_label(args_span
, message
);
629 // Add a span label to the use of the captured variable, if it exists.
630 pub(super) fn var_span_label(
632 err
: &mut DiagnosticBuilder
<'_
>,
633 message
: impl Into
<String
>,
635 if let UseSpans
::ClosureUse { var_span, .. }
= self {
636 err
.span_label(var_span
, message
);
640 /// Returns `false` if this place is not used in a closure.
641 pub(super) fn for_closure(&self) -> bool
{
643 UseSpans
::ClosureUse { generator_kind, .. }
=> generator_kind
.is_none(),
648 /// Returns `false` if this place is not used in a generator.
649 pub(super) fn for_generator(&self) -> bool
{
651 UseSpans
::ClosureUse { generator_kind, .. }
=> generator_kind
.is_some(),
656 /// Describe the span associated with a use of a place.
657 pub(super) fn describe(&self) -> String
{
659 UseSpans
::ClosureUse { generator_kind, .. }
=> {
660 if generator_kind
.is_some() {
661 " in generator".to_string()
663 " in closure".to_string()
670 pub(super) fn or_else
<F
>(self, if_other
: F
) -> Self
675 closure @ UseSpans
::ClosureUse { .. }
=> closure
,
676 UseSpans
::PatUse(_
) | UseSpans
::OtherUse(_
) => if_other(),
677 fn_self @ UseSpans
::FnSelfUse { .. }
=> fn_self
,
682 pub(super) enum BorrowedContentSource
<'tcx
> {
686 OverloadedDeref(Ty
<'tcx
>),
687 OverloadedIndex(Ty
<'tcx
>),
690 impl BorrowedContentSource
<'tcx
> {
691 pub(super) fn describe_for_unnamed_place(&self, tcx
: TyCtxt
<'_
>) -> String
{
693 BorrowedContentSource
::DerefRawPointer
=> "a raw pointer".to_string(),
694 BorrowedContentSource
::DerefSharedRef
=> "a shared reference".to_string(),
695 BorrowedContentSource
::DerefMutableRef
=> "a mutable reference".to_string(),
696 BorrowedContentSource
::OverloadedDeref(ty
) => match ty
.kind() {
697 ty
::Adt(def
, _
) if tcx
.is_diagnostic_item(sym
::Rc
, def
.did
) => {
698 "an `Rc`".to_string()
700 ty
::Adt(def
, _
) if tcx
.is_diagnostic_item(sym
::Arc
, def
.did
) => {
701 "an `Arc`".to_string()
703 _
=> format
!("dereference of `{}`", ty
),
705 BorrowedContentSource
::OverloadedIndex(ty
) => format
!("index of `{}`", ty
),
709 pub(super) fn describe_for_named_place(&self) -> Option
<&'
static str> {
711 BorrowedContentSource
::DerefRawPointer
=> Some("raw pointer"),
712 BorrowedContentSource
::DerefSharedRef
=> Some("shared reference"),
713 BorrowedContentSource
::DerefMutableRef
=> Some("mutable reference"),
714 // Overloaded deref and index operators should be evaluated into a
715 // temporary. So we don't need a description here.
716 BorrowedContentSource
::OverloadedDeref(_
)
717 | BorrowedContentSource
::OverloadedIndex(_
) => None
,
721 pub(super) fn describe_for_immutable_place(&self, tcx
: TyCtxt
<'_
>) -> String
{
723 BorrowedContentSource
::DerefRawPointer
=> "a `*const` pointer".to_string(),
724 BorrowedContentSource
::DerefSharedRef
=> "a `&` reference".to_string(),
725 BorrowedContentSource
::DerefMutableRef
=> {
726 bug
!("describe_for_immutable_place: DerefMutableRef isn't immutable")
728 BorrowedContentSource
::OverloadedDeref(ty
) => match ty
.kind() {
729 ty
::Adt(def
, _
) if tcx
.is_diagnostic_item(sym
::Rc
, def
.did
) => {
730 "an `Rc`".to_string()
732 ty
::Adt(def
, _
) if tcx
.is_diagnostic_item(sym
::Arc
, def
.did
) => {
733 "an `Arc`".to_string()
735 _
=> format
!("a dereference of `{}`", ty
),
737 BorrowedContentSource
::OverloadedIndex(ty
) => format
!("an index of `{}`", ty
),
741 fn from_call(func
: Ty
<'tcx
>, tcx
: TyCtxt
<'tcx
>) -> Option
<Self> {
743 ty
::FnDef(def_id
, substs
) => {
744 let trait_id
= tcx
.trait_of_item(def_id
)?
;
746 let lang_items
= tcx
.lang_items();
747 if Some(trait_id
) == lang_items
.deref_trait()
748 || Some(trait_id
) == lang_items
.deref_mut_trait()
750 Some(BorrowedContentSource
::OverloadedDeref(substs
.type_at(0)))
751 } else if Some(trait_id
) == lang_items
.index_trait()
752 || Some(trait_id
) == lang_items
.index_mut_trait()
754 Some(BorrowedContentSource
::OverloadedIndex(substs
.type_at(0)))
764 impl<'cx
, 'tcx
> MirBorrowckCtxt
<'cx
, 'tcx
> {
765 /// Finds the spans associated to a move or copy of move_place at location.
766 pub(super) fn move_spans(
768 moved_place
: PlaceRef
<'tcx
>, // Could also be an upvar.
770 ) -> UseSpans
<'tcx
> {
771 use self::UseSpans
::*;
773 let stmt
= match self.body
[location
.block
].statements
.get(location
.statement_index
) {
775 None
=> return OtherUse(self.body
.source_info(location
).span
),
778 debug
!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place
, location
, stmt
);
779 if let StatementKind
::Assign(box (_
, Rvalue
::Aggregate(ref kind
, ref places
))) = stmt
.kind
{
781 box AggregateKind
::Closure(def_id
, _
)
782 | box AggregateKind
::Generator(def_id
, _
, _
) => {
783 debug
!("move_spans: def_id={:?} places={:?}", def_id
, places
);
784 if let Some((args_span
, generator_kind
, var_span
)) =
785 self.closure_span(*def_id
, moved_place
, places
)
787 return ClosureUse { generator_kind, args_span, var_span }
;
795 if moved_place
.projection
.iter().any(|p
| matches
!(p
, ProjectionElem
::Downcast(..))) {
796 PatUse(stmt
.source_info
.span
)
798 OtherUse(stmt
.source_info
.span
)
801 // We are trying to find MIR of the form:
803 // _temp = _moved_val;
805 // FnSelfCall(_temp, ...)
808 // where `_moved_val` is the place we generated the move error for,
809 // `_temp` is some other local, and `FnSelfCall` is a function
810 // that has a `self` parameter.
812 let target_temp
= match stmt
.kind
{
813 StatementKind
::Assign(box (temp
, _
)) if temp
.as_local().is_some() => {
814 temp
.as_local().unwrap()
816 _
=> return normal_ret
,
819 debug
!("move_spans: target_temp = {:?}", target_temp
);
821 if let Some(Terminator
{
822 kind
: TerminatorKind
::Call { fn_span, from_hir_call, .. }
, ..
823 }) = &self.body
[location
.block
].terminator
825 let (method_did
, method_substs
) = if let Some(info
) =
826 crate::util
::find_self_call(self.infcx
.tcx
, &self.body
, target_temp
, location
.block
)
833 let tcx
= self.infcx
.tcx
;
834 let parent
= tcx
.parent(method_did
);
835 let is_fn_once
= parent
== tcx
.lang_items().fn_once_trait();
836 let is_operator
= !from_hir_call
837 && parent
.map_or(false, |p
| tcx
.lang_items().group(LangItemGroup
::Op
).contains(&p
));
838 let is_deref
= !from_hir_call
&& tcx
.is_diagnostic_item(sym
::deref_method
, method_did
);
839 let fn_call_span
= *fn_span
;
841 let self_arg
= tcx
.fn_arg_names(method_did
)[0];
844 "terminator = {:?} from_hir_call={:?}",
845 self.body
[location
.block
].terminator
, from_hir_call
848 // Check for a 'special' use of 'self' -
849 // an FnOnce call, an operator (e.g. `<<`), or a
851 let kind
= if is_fn_once
{
852 Some(FnSelfUseKind
::FnOnceCall
)
853 } else if is_operator
{
854 Some(FnSelfUseKind
::Operator { self_arg }
)
857 tcx
.get_diagnostic_item(sym
::deref_target
).and_then(|deref_target
| {
858 Instance
::resolve(tcx
, self.param_env
, deref_target
, method_substs
)
861 if let Some(Ok(instance
)) = deref_target
{
862 let deref_target_ty
= instance
.ty(tcx
, self.param_env
);
863 Some(FnSelfUseKind
::DerefCoercion
{
864 deref_target
: tcx
.def_span(instance
.def_id()),
874 let kind
= kind
.unwrap_or_else(|| {
875 // This isn't a 'special' use of `self`
876 debug
!("move_spans: method_did={:?}, fn_call_span={:?}", method_did
, fn_call_span
);
877 let implicit_into_iter
= matches
!(
878 fn_call_span
.desugaring_kind(),
879 Some(DesugaringKind
::ForLoop(ForLoopLoc
::IntoIter
))
881 FnSelfUseKind
::Normal { self_arg, implicit_into_iter }
885 var_span
: stmt
.source_info
.span
,
892 .guess_head_span(self.infcx
.tcx
.def_span(method_did
)),
899 /// Finds the span of arguments of a closure (within `maybe_closure_span`)
900 /// and its usage of the local assigned at `location`.
901 /// This is done by searching in statements succeeding `location`
902 /// and originating from `maybe_closure_span`.
903 pub(super) fn borrow_spans(&self, use_span
: Span
, location
: Location
) -> UseSpans
<'tcx
> {
904 use self::UseSpans
::*;
905 debug
!("borrow_spans: use_span={:?} location={:?}", use_span
, location
);
907 let target
= match self.body
[location
.block
].statements
.get(location
.statement_index
) {
908 Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }
) => {
909 if let Some(local
) = place
.as_local() {
912 return OtherUse(use_span
);
915 _
=> return OtherUse(use_span
),
918 if self.body
.local_kind(target
) != LocalKind
::Temp
{
919 // operands are always temporaries.
920 return OtherUse(use_span
);
923 for stmt
in &self.body
[location
.block
].statements
[location
.statement_index
+ 1..] {
924 if let StatementKind
::Assign(box (_
, Rvalue
::Aggregate(ref kind
, ref places
))) =
927 let (def_id
, is_generator
) = match kind
{
928 box AggregateKind
::Closure(def_id
, _
) => (def_id
, false),
929 box AggregateKind
::Generator(def_id
, _
, _
) => (def_id
, true),
934 "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
935 def_id
, is_generator
, places
937 if let Some((args_span
, generator_kind
, var_span
)) =
938 self.closure_span(*def_id
, Place
::from(target
).as_ref(), places
)
940 return ClosureUse { generator_kind, args_span, var_span }
;
942 return OtherUse(use_span
);
946 if use_span
!= stmt
.source_info
.span
{
954 /// Finds the span of a captured variable within a closure or generator.
958 target_place
: PlaceRef
<'tcx
>,
959 places
: &Vec
<Operand
<'tcx
>>,
960 ) -> Option
<(Span
, Option
<GeneratorKind
>, Span
)> {
962 "closure_span: def_id={:?} target_place={:?} places={:?}",
963 def_id
, target_place
, places
965 let local_did
= def_id
.as_local()?
;
966 let hir_id
= self.infcx
.tcx
.hir().local_def_id_to_hir_id(local_did
);
967 let expr
= &self.infcx
.tcx
.hir().expect_expr(hir_id
).kind
;
968 debug
!("closure_span: hir_id={:?} expr={:?}", hir_id
, expr
);
969 if let hir
::ExprKind
::Closure(.., body_id
, args_span
, _
) = expr
{
970 for ((upvar_hir_id
, upvar
), place
) in
971 self.infcx
.tcx
.upvars_mentioned(def_id
)?
.iter().zip(places
)
974 Operand
::Copy(place
) | Operand
::Move(place
)
975 if target_place
== place
.as_ref() =>
977 debug
!("closure_span: found captured local {:?}", place
);
978 let body
= self.infcx
.tcx
.hir().body(*body_id
);
979 let generator_kind
= body
.generator_kind();
980 let upvar_id
= ty
::UpvarId
{
981 var_path
: ty
::UpvarPath { hir_id: *upvar_hir_id }
,
982 closure_expr_id
: local_did
,
985 // If we have a more specific span available, point to that.
986 // We do this even though this span might be part of a borrow error
987 // message rather than a move error message. Our goal is to point
988 // to a span that shows why the upvar is used in the closure,
989 // so a move-related span is as good as any (and potentially better,
990 // if the overall error is due to a move of the upvar).
992 match self.infcx
.tcx
.typeck(local_did
).upvar_capture(upvar_id
) {
993 ty
::UpvarCapture
::ByValue(Some(span
)) => span
,
996 return Some((*args_span
, generator_kind
, usage_span
));
1005 /// Helper to retrieve span(s) of given borrow from the current MIR
1007 pub(super) fn retrieve_borrow_spans(&self, borrow
: &BorrowData
<'_
>) -> UseSpans
<'tcx
> {
1008 let span
= self.body
.source_info(borrow
.reserve_location
).span
;
1009 self.borrow_spans(span
, borrow
.reserve_location
)