]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/diagnostics/mod.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / mod.rs
CommitLineData
60c5eb7d
XL
1//! Borrow checker diagnostics.
2
04454e1e 3use itertools::Itertools;
5e7ed085
FG
4use rustc_const_eval::util::{call_kind, CallDesugaringKind};
5use rustc_errors::{Applicability, Diagnostic};
dfeec247 6use rustc_hir as hir;
064997fb 7use rustc_hir::def::{CtorKind, Namespace};
dfeec247 8use rustc_hir::GeneratorKind;
353b0b11 9use rustc_index::vec::IndexSlice;
9c376795 10use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
064997fb 11use rustc_middle::mir::tcx::PlaceTy;
ba9703b0 12use rustc_middle::mir::{
353b0b11
FG
13 AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
14 PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
ba9703b0
XL
15};
16use rustc_middle::ty::print::Print;
353b0b11 17use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
c295e0f8 18use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
064997fb
FG
19use rustc_span::def_id::LocalDefId;
20use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
353b0b11 21use rustc_target::abi::{FieldIdx, VariantIdx};
9c376795
FG
22use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
23use rustc_trait_selection::traits::{
24 type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
25};
ff7c6d11 26
94b46f34 27use super::borrow_set::BorrowData;
e74abb32 28use super::MirBorrowckCtxt;
ff7c6d11 29
a2a8927a 30mod find_all_local_uses;
60c5eb7d 31mod find_use;
60c5eb7d 32mod outlives_suggestion;
dfeec247
XL
33mod region_name;
34mod var_name;
60c5eb7d 35
94222f64 36mod bound_region_errors;
60c5eb7d 37mod conflict_errors;
dfeec247 38mod explain_borrow;
60c5eb7d
XL
39mod move_errors;
40mod mutability_errors;
41mod region_errors;
60c5eb7d 42
923072b8
FG
43pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
44pub(crate) use mutability_errors::AccessKind;
45pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
46pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
47pub(crate) use region_name::{RegionName, RegionNameSource};
48pub(crate) use rustc_const_eval::util::CallKind;
60c5eb7d 49
064997fb
FG
50pub(super) struct DescribePlaceOpt {
51 pub including_downcast: bool,
52
53 /// Enable/Disable tuple fields.
54 /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
55 pub including_tuple_field: bool,
56}
57
58pub(super) struct IncludingTupleField(pub(super) bool);
0bf4aa26 59
dc9dc135 60impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
0731742a
XL
61 /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
62 /// is moved after being invoked.
0bf4aa26
XL
63 ///
64 /// ```text
65 /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
66 /// its environment
67 /// --> $DIR/issue-42065.rs:16:29
68 /// |
69 /// LL | for (key, value) in dict {
70 /// | ^^^^
71 /// ```
0731742a 72 pub(super) fn add_moved_or_invoked_closure_note(
0bf4aa26
XL
73 &self,
74 location: Location,
74b04a01 75 place: PlaceRef<'tcx>,
5e7ed085 76 diag: &mut Diagnostic,
487cf647 77 ) -> bool {
0731742a 78 debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
dc9dc135
XL
79 let mut target = place.local_or_deref_local();
80 for stmt in &self.body[location.block].statements[location.statement_index..] {
0731742a 81 debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
dfeec247 82 if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
0731742a 83 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
0bf4aa26 84 match from {
487cf647 85 Operand::Copy(place) | Operand::Move(place)
dfeec247
XL
86 if target == place.local_or_deref_local() =>
87 {
88 target = into.local_or_deref_local()
89 }
90 _ => {}
0bf4aa26
XL
91 }
92 }
93 }
94
0731742a 95 // Check if we are attempting to call a closure after it has been invoked.
dc9dc135 96 let terminator = self.body[location.block].terminator();
0731742a 97 debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
0bf4aa26 98 if let TerminatorKind::Call {
6a06907d 99 func: Operand::Constant(box Constant { literal, .. }),
0bf4aa26
XL
100 args,
101 ..
dfeec247
XL
102 } = &terminator.kind
103 {
6a06907d 104 if let ty::FnDef(id, _) = *literal.ty().kind() {
1b1a35ee 105 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
04454e1e 106 if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
1b1a35ee 107 let closure = match args.first() {
487cf647 108 Some(Operand::Copy(place) | Operand::Move(place))
1b1a35ee
XL
109 if target == place.local_or_deref_local() =>
110 {
111 place.local_or_deref_local().unwrap()
112 }
487cf647 113 _ => return false,
1b1a35ee 114 };
0bf4aa26 115
1b1a35ee
XL
116 debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
117 if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
118 let did = did.expect_local();
9ffffee4 119 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
1b1a35ee
XL
120 diag.span_note(
121 *span,
122 &format!(
123 "closure cannot be invoked more than once because it moves the \
124 variable `{}` out of its environment",
5869c6ff 125 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
1b1a35ee
XL
126 ),
127 );
487cf647 128 return true;
1b1a35ee 129 }
0bf4aa26
XL
130 }
131 }
132 }
133 }
0731742a
XL
134
135 // Check if we are just moving a closure after it has been invoked.
136 if let Some(target) = target {
1b1a35ee 137 if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
f9f354fc 138 let did = did.expect_local();
9ffffee4 139 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
0731742a
XL
140 diag.span_note(
141 *span,
142 &format!(
143 "closure cannot be moved more than once as it is not `Copy` due to \
144 moving the variable `{}` out of its environment",
5869c6ff 145 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
0731742a
XL
146 ),
147 );
487cf647 148 return true;
0731742a
XL
149 }
150 }
151 }
487cf647 152 false
0bf4aa26
XL
153 }
154
ba9703b0
XL
155 /// End-user visible description of `place` if one can be found.
156 /// If the place is a temporary for instance, `"value"` will be returned.
157 pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
158 match self.describe_place(place_ref) {
159 Some(mut descr) => {
160 // Surround descr with `backticks`.
161 descr.reserve(2);
1b1a35ee
XL
162 descr.insert(0, '`');
163 descr.push('`');
ba9703b0
XL
164 descr
165 }
166 None => "value".to_string(),
167 }
168 }
169
170 /// End-user visible description of `place` if one can be found.
04454e1e 171 /// If the place is a temporary for instance, `None` will be returned.
74b04a01 172 pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
064997fb
FG
173 self.describe_place_with_options(
174 place_ref,
175 DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
176 )
8faf50e0
XL
177 }
178
04454e1e
FG
179 /// End-user visible description of `place` if one can be found. If the place is a temporary
180 /// for instance, `None` will be returned.
181 /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is
0bf4aa26 182 /// `Downcast` and `IncludingDowncast` is true
8faf50e0
XL
183 pub(super) fn describe_place_with_options(
184 &self,
74b04a01 185 place: PlaceRef<'tcx>,
064997fb 186 opt: DescribePlaceOpt,
8faf50e0 187 ) -> Option<String> {
04454e1e
FG
188 let local = place.local;
189 let mut autoderef_index = None;
ff7c6d11 190 let mut buf = String::new();
04454e1e 191 let mut ok = self.append_local_to_string(local, &mut buf);
ff7c6d11 192
04454e1e
FG
193 for (index, elem) in place.projection.into_iter().enumerate() {
194 match elem {
195 ProjectionElem::Deref => {
196 if index == 0 {
197 if self.body.local_decls[local].is_ref_for_guard() {
198 continue;
ff7c6d11 199 }
353b0b11
FG
200 if let LocalInfo::StaticRef { def_id, .. } =
201 *self.body.local_decls[local].local_info()
04454e1e 202 {
353b0b11 203 buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
04454e1e
FG
204 ok = Ok(());
205 continue;
8faf50e0 206 }
ff7c6d11 207 }
04454e1e
FG
208 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
209 local,
210 projection: place.projection.split_at(index + 1).0,
211 }) {
212 let var_index = field.index();
213 buf = self.upvars[var_index].place.to_string(self.infcx.tcx);
214 ok = Ok(());
215 if !self.upvars[var_index].by_ref {
216 buf.insert(0, '*');
ff7c6d11 217 }
04454e1e
FG
218 } else {
219 if autoderef_index.is_none() {
220 autoderef_index =
221 match place.projection.into_iter().rev().find_position(|elem| {
222 !matches!(
223 elem,
224 ProjectionElem::Deref | ProjectionElem::Downcast(..)
225 )
226 }) {
227 Some((index, _)) => Some(place.projection.len() - index),
228 None => Some(0),
229 };
230 }
231 if index >= autoderef_index.unwrap() {
232 buf.insert(0, '*');
ff7c6d11 233 }
ff7c6d11 234 }
04454e1e 235 }
064997fb 236 ProjectionElem::Downcast(..) if opt.including_downcast => return None,
04454e1e 237 ProjectionElem::Downcast(..) => (),
2b03887a 238 ProjectionElem::OpaqueCast(..) => (),
04454e1e
FG
239 ProjectionElem::Field(field, _ty) => {
240 // FIXME(project-rfc_2229#36): print capture precisely here.
241 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
242 local,
243 projection: place.projection.split_at(index + 1).0,
244 }) {
245 buf = self.upvars[field.index()].place.to_string(self.infcx.tcx);
246 ok = Ok(());
247 } else {
248 let field_name = self.describe_field(
249 PlaceRef { local, projection: place.projection.split_at(index).0 },
250 *field,
064997fb 251 IncludingTupleField(opt.including_tuple_field),
04454e1e 252 );
064997fb
FG
253 if let Some(field_name_str) = field_name {
254 buf.push('.');
255 buf.push_str(&field_name_str);
256 }
ff7c6d11 257 }
04454e1e
FG
258 }
259 ProjectionElem::Index(index) => {
260 buf.push('[');
261 if self.append_local_to_string(*index, &mut buf).is_err() {
262 buf.push('_');
263 }
264 buf.push(']');
265 }
266 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
267 // Since it isn't possible to borrow an element on a particular index and
268 // then use another while the borrow is held, don't output indices details
269 // to avoid confusing the end-user
270 buf.push_str("[..]");
271 }
ff7c6d11
XL
272 }
273 }
04454e1e 274 ok.ok().map(|_| buf)
ff7c6d11
XL
275 }
276
064997fb
FG
277 fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
278 for elem in place.projection.into_iter() {
279 match elem {
280 ProjectionElem::Downcast(Some(name), _) => {
281 return Some(*name);
282 }
283 _ => {}
284 }
285 }
286 None
287 }
288
0bf4aa26 289 /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
dc9dc135 290 /// a name, or its name was generated by the compiler, then `Err` is returned
60c5eb7d
XL
291 fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
292 let decl = &self.body.local_decls[local];
293 match self.local_names[local] {
294 Some(name) if !decl.from_compiler_desugaring() => {
a2a8927a 295 buf.push_str(name.as_str());
ff7c6d11
XL
296 Ok(())
297 }
dc9dc135 298 _ => Err(()),
ff7c6d11
XL
299 }
300 }
301
0bf4aa26 302 /// End-user visible description of the `field`nth field of `base`
064997fb
FG
303 fn describe_field(
304 &self,
305 place: PlaceRef<'tcx>,
353b0b11 306 field: FieldIdx,
064997fb
FG
307 including_tuple_field: IncludingTupleField,
308 ) -> Option<String> {
04454e1e
FG
309 let place_ty = match place {
310 PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
dfeec247 311 PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
04454e1e
FG
312 ProjectionElem::Deref
313 | ProjectionElem::Index(..)
0531ce1d
XL
314 | ProjectionElem::ConstantIndex { .. }
315 | ProjectionElem::Subslice { .. } => {
04454e1e 316 PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
ff7c6d11 317 }
04454e1e 318 ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
2b03887a 319 ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
04454e1e 320 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
ff7c6d11 321 },
04454e1e 322 };
064997fb
FG
323 self.describe_field_from_ty(
324 place_ty.ty,
325 field,
326 place_ty.variant_index,
327 including_tuple_field,
328 )
ff7c6d11
XL
329 }
330
0bf4aa26 331 /// End-user visible description of the `field_index`nth field of `ty`
532ac7d7
XL
332 fn describe_field_from_ty(
333 &self,
48663c56 334 ty: Ty<'_>,
353b0b11 335 field: FieldIdx,
dfeec247 336 variant_index: Option<VariantIdx>,
064997fb
FG
337 including_tuple_field: IncludingTupleField,
338 ) -> Option<String> {
ff7c6d11
XL
339 if ty.is_box() {
340 // If the type is a box, the field is described from the boxed type
064997fb 341 self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field)
ff7c6d11 342 } else {
1b1a35ee 343 match *ty.kind() {
532ac7d7
XL
344 ty::Adt(def, _) => {
345 let variant = if let Some(idx) = variant_index {
346 assert!(def.is_enum());
5e7ed085 347 &def.variant(idx)
532ac7d7
XL
348 } else {
349 def.non_enum_variant()
350 };
487cf647 351 if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) {
064997fb
FG
352 return None;
353 }
353b0b11 354 Some(variant.fields[field].name.to_string())
dfeec247 355 }
064997fb 356 ty::Tuple(_) => Some(field.index().to_string()),
b7449926 357 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
064997fb 358 self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
ff7c6d11 359 }
dfeec247 360 ty::Array(ty, _) | ty::Slice(ty) => {
064997fb 361 self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
dfeec247 362 }
b7449926 363 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
fc512014
XL
364 // We won't be borrowck'ing here if the closure came from another crate,
365 // so it's safe to call `expect_local`.
366 //
367 // We know the field exists so it's safe to call operator[] and `unwrap` here.
064997fb 368 let def_id = def_id.expect_local();
9ffffee4
FG
369 let var_id =
370 self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
ff7c6d11 371
064997fb 372 Some(self.infcx.tcx.hir().name(var_id).to_string())
ff7c6d11
XL
373 }
374 _ => {
375 // Might need a revision when the fields in trait RFC is implemented
376 // (https://github.com/rust-lang/rfcs/pull/1546)
dfeec247 377 bug!("End-user description not implemented for field access on `{:?}`", ty);
ff7c6d11
XL
378 }
379 }
380 }
381 }
382
dc9dc135
XL
383 /// Add a note that a type does not implement `Copy`
384 pub(super) fn note_type_does_not_implement_copy(
0bf4aa26 385 &self,
5e7ed085 386 err: &mut Diagnostic,
dc9dc135
XL
387 place_desc: &str,
388 ty: Ty<'tcx>,
389 span: Option<Span>,
1b1a35ee 390 move_prefix: &str,
dc9dc135
XL
391 ) {
392 let message = format!(
9c376795 393 "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait",
0bf4aa26 394 );
dc9dc135
XL
395 if let Some(span) = span {
396 err.span_label(span, message);
397 } else {
398 err.note(&message);
0bf4aa26
XL
399 }
400 }
416331ca
XL
401
402 pub(super) fn borrowed_content_source(
403 &self,
74b04a01 404 deref_base: PlaceRef<'tcx>,
416331ca
XL
405 ) -> BorrowedContentSource<'tcx> {
406 let tcx = self.infcx.tcx;
407
408 // Look up the provided place and work out the move path index for it,
409 // we'll use this to check whether it was originally from an overloaded
410 // operator.
411 match self.move_data.rev_lookup.find(deref_base) {
412 LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
413 debug!("borrowed_content_source: mpi={:?}", mpi);
414
415 for i in &self.move_data.init_path_map[mpi] {
416 let init = &self.move_data.inits[*i];
417 debug!("borrowed_content_source: init={:?}", init);
418 // We're only interested in statements that initialized a value, not the
419 // initializations from arguments.
5e7ed085 420 let InitLocation::Statement(loc) = init.location else { continue };
416331ca
XL
421
422 let bbd = &self.body[loc.block];
423 let is_terminator = bbd.statements.len() == loc.statement_index;
424 debug!(
425 "borrowed_content_source: loc={:?} is_terminator={:?}",
dfeec247 426 loc, is_terminator,
416331ca
XL
427 );
428 if !is_terminator {
429 continue;
430 } else if let Some(Terminator {
487cf647 431 kind: TerminatorKind::Call { func, from_hir_call: false, .. },
416331ca 432 ..
487cf647 433 }) = &bbd.terminator
dfeec247
XL
434 {
435 if let Some(source) =
f9f354fc 436 BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
dfeec247 437 {
416331ca
XL
438 return source;
439 }
440 }
441 }
442 }
443 // Base is a `static` so won't be from an overloaded operator
444 _ => (),
445 };
446
447 // If we didn't find an overloaded deref or index, then assume it's a
448 // built in deref and check the type of the base.
5869c6ff 449 let base_ty = deref_base.ty(self.body, tcx).ty;
416331ca
XL
450 if base_ty.is_unsafe_ptr() {
451 BorrowedContentSource::DerefRawPointer
452 } else if base_ty.is_mutable_ptr() {
453 BorrowedContentSource::DerefMutableRef
454 } else {
455 BorrowedContentSource::DerefSharedRef
456 }
457 }
0bf4aa26
XL
458
459 /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
460 /// name where required.
dc9dc135 461 pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
5e7ed085 462 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
532ac7d7 463
0bf4aa26
XL
464 // We need to add synthesized lifetimes where appropriate. We do
465 // this by hooking into the pretty printer and telling it to label the
466 // lifetimes without names with the value `'0`.
5099ac24
FG
467 if let ty::Ref(region, ..) = ty.kind() {
468 match **region {
469 ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
353b0b11
FG
470 | ty::RePlaceholder(ty::PlaceholderRegion {
471 bound: ty::BoundRegion { kind: br, .. },
472 ..
473 }) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
5099ac24
FG
474 _ => {}
475 }
0bf4aa26 476 }
532ac7d7 477
5e7ed085 478 ty.print(printer).unwrap().into_buffer()
0bf4aa26
XL
479 }
480
9fa01778 481 /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
0bf4aa26 482 /// synthesized lifetime name where required.
dc9dc135 483 pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
5e7ed085 484 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
532ac7d7 485
5099ac24
FG
486 let region = if let ty::Ref(region, ..) = ty.kind() {
487 match **region {
488 ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
353b0b11
FG
489 | ty::RePlaceholder(ty::PlaceholderRegion {
490 bound: ty::BoundRegion { kind: br, .. },
491 ..
492 }) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
5099ac24 493 _ => {}
532ac7d7 494 }
5099ac24
FG
495 region
496 } else {
497 bug!("ty for annotation of borrow region is not a reference");
532ac7d7
XL
498 };
499
5e7ed085 500 region.print(printer).unwrap().into_buffer()
0bf4aa26 501 }
b7449926
XL
502}
503
f035d41b 504/// The span(s) associated to a use of a place.
b7449926 505#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1b1a35ee 506pub(super) enum UseSpans<'tcx> {
f035d41b 507 /// The access is caused by capturing a variable for a closure.
b7449926 508 ClosureUse {
f035d41b 509 /// This is true if the captured variable was from a generator.
e74abb32 510 generator_kind: Option<GeneratorKind>,
f035d41b
XL
511 /// The span of the args of the closure, including the `move` keyword if
512 /// it's present.
b7449926 513 args_span: Span,
17df50a5
XL
514 /// The span of the use resulting in capture kind
515 /// Check `ty::CaptureInfo` for more details
516 capture_kind_span: Span,
517 /// The span of the use resulting in the captured path
518 /// Check `ty::CaptureInfo` for more details
519 path_span: Span,
f035d41b
XL
520 },
521 /// The access is caused by using a variable as the receiver of a method
522 /// that takes 'self'
523 FnSelfUse {
524 /// The span of the variable being moved
b7449926 525 var_span: Span,
f035d41b
XL
526 /// The span of the method call on the variable
527 fn_call_span: Span,
528 /// The definition span of the method being called
529 fn_span: Span,
5099ac24 530 kind: CallKind<'tcx>,
b7449926 531 },
f035d41b
XL
532 /// This access is caused by a `match` or `if let` pattern.
533 PatUse(Span),
534 /// This access has a single span associated to it: common case.
b7449926
XL
535 OtherUse(Span),
536}
537
1b1a35ee 538impl UseSpans<'_> {
b7449926
XL
539 pub(super) fn args_or_use(self) -> Span {
540 match self {
f035d41b
XL
541 UseSpans::ClosureUse { args_span: span, .. }
542 | UseSpans::PatUse(span)
f035d41b 543 | UseSpans::OtherUse(span) => span,
5099ac24
FG
544 UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
545 fn_call_span
546 }
1b1a35ee 547 UseSpans::FnSelfUse { var_span, .. } => var_span,
b7449926
XL
548 }
549 }
550
17df50a5
XL
551 /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
552 pub(super) fn var_or_use_path_span(self) -> Span {
553 match self {
554 UseSpans::ClosureUse { path_span: span, .. }
555 | UseSpans::PatUse(span)
556 | UseSpans::OtherUse(span) => span,
5099ac24
FG
557 UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
558 fn_call_span
559 }
17df50a5
XL
560 UseSpans::FnSelfUse { var_span, .. } => var_span,
561 }
562 }
563
564 /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
b7449926
XL
565 pub(super) fn var_or_use(self) -> Span {
566 match self {
17df50a5 567 UseSpans::ClosureUse { capture_kind_span: span, .. }
f035d41b 568 | UseSpans::PatUse(span)
f035d41b 569 | UseSpans::OtherUse(span) => span,
5099ac24
FG
570 UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
571 fn_call_span
572 }
1b1a35ee 573 UseSpans::FnSelfUse { var_span, .. } => var_span,
b7449926
XL
574 }
575 }
576
e74abb32
XL
577 pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
578 match self {
579 UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
580 _ => None,
581 }
582 }
583
487cf647 584 /// Add a span label to the arguments of the closure, if it exists.
5e7ed085 585 pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) {
b7449926
XL
586 if let UseSpans::ClosureUse { args_span, .. } = self {
587 err.span_label(args_span, message);
588 }
589 }
590
487cf647
FG
591 /// Add a span label to the use of the captured variable, if it exists.
592 /// only adds label to the `path_span`
593 pub(super) fn var_path_only_subdiag(
594 self,
595 err: &mut Diagnostic,
596 action: crate::InitializationRequiringAction,
597 ) {
598 use crate::session_diagnostics::CaptureVarPathUseCause::*;
599 use crate::InitializationRequiringAction::*;
600 if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self {
601 match generator_kind {
602 Some(_) => {
603 err.subdiagnostic(match action {
604 Borrow => BorrowInGenerator { path_span },
605 MatchOn | Use => UseInGenerator { path_span },
606 Assignment => AssignInGenerator { path_span },
607 PartialAssignment => AssignPartInGenerator { path_span },
608 });
609 }
610 None => {
611 err.subdiagnostic(match action {
612 Borrow => BorrowInClosure { path_span },
613 MatchOn | Use => UseInClosure { path_span },
614 Assignment => AssignInClosure { path_span },
615 PartialAssignment => AssignPartInClosure { path_span },
616 });
617 }
618 }
17df50a5
XL
619 }
620 }
621
487cf647 622 /// Add a span label to the use of the captured variable, if it exists.
9fa01778
XL
623 pub(super) fn var_span_label(
624 self,
5e7ed085 625 err: &mut Diagnostic,
9fa01778 626 message: impl Into<String>,
17df50a5 627 kind_desc: impl Into<String>,
9fa01778 628 ) {
17df50a5
XL
629 if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
630 if capture_kind_span == path_span {
631 err.span_label(capture_kind_span, message);
632 } else {
633 let capture_kind_label =
634 format!("capture is {} because of use here", kind_desc.into());
635 let path_label = message;
636 err.span_label(capture_kind_span, capture_kind_label);
637 err.span_label(path_span, path_label);
638 }
b7449926
XL
639 }
640 }
641
487cf647
FG
642 /// Add a subdiagnostic to the use of the captured variable, if it exists.
643 pub(super) fn var_subdiag(
644 self,
645 err: &mut Diagnostic,
646 kind: Option<rustc_middle::mir::BorrowKind>,
647 f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause,
648 ) {
649 use crate::session_diagnostics::CaptureVarKind::*;
650 if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self {
651 if capture_kind_span != path_span {
652 err.subdiagnostic(match kind {
653 Some(kd) => match kd {
654 rustc_middle::mir::BorrowKind::Shared
655 | rustc_middle::mir::BorrowKind::Shallow
656 | rustc_middle::mir::BorrowKind::Unique => {
657 Immute { kind_span: capture_kind_span }
658 }
659
660 rustc_middle::mir::BorrowKind::Mut { .. } => {
661 Mut { kind_span: capture_kind_span }
662 }
663 },
664 None => Move { kind_span: capture_kind_span },
665 });
666 };
667 err.subdiagnostic(f(generator_kind, path_span));
668 }
669 }
670
9fa01778 671 /// Returns `false` if this place is not used in a closure.
dc9dc135 672 pub(super) fn for_closure(&self) -> bool {
0bf4aa26 673 match *self {
e74abb32 674 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
0bf4aa26
XL
675 _ => false,
676 }
677 }
678
9fa01778 679 /// Returns `false` if this place is not used in a generator.
dc9dc135 680 pub(super) fn for_generator(&self) -> bool {
0bf4aa26 681 match *self {
e74abb32 682 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
0bf4aa26
XL
683 _ => false,
684 }
685 }
686
687 /// Describe the span associated with a use of a place.
064997fb 688 pub(super) fn describe(&self) -> &str {
0bf4aa26 689 match *self {
dfeec247
XL
690 UseSpans::ClosureUse { generator_kind, .. } => {
691 if generator_kind.is_some() {
064997fb 692 " in generator"
dfeec247 693 } else {
064997fb 694 " in closure"
dfeec247
XL
695 }
696 }
064997fb 697 _ => "",
b7449926
XL
698 }
699 }
700
701 pub(super) fn or_else<F>(self, if_other: F) -> Self
702 where
703 F: FnOnce() -> Self,
704 {
705 match self {
706 closure @ UseSpans::ClosureUse { .. } => closure,
f035d41b
XL
707 UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
708 fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
b7449926
XL
709 }
710 }
711}
712
416331ca
XL
713pub(super) enum BorrowedContentSource<'tcx> {
714 DerefRawPointer,
715 DerefMutableRef,
716 DerefSharedRef,
717 OverloadedDeref(Ty<'tcx>),
718 OverloadedIndex(Ty<'tcx>),
719}
720
a2a8927a 721impl<'tcx> BorrowedContentSource<'tcx> {
ba9703b0 722 pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
416331ca 723 match *self {
74b04a01
XL
724 BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
725 BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
726 BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
a2a8927a
XL
727 BorrowedContentSource::OverloadedDeref(ty) => ty
728 .ty_adt_def()
5e7ed085 729 .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
9c376795 730 name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
a2a8927a
XL
731 _ => None,
732 })
9c376795
FG
733 .unwrap_or_else(|| format!("dereference of `{ty}`")),
734 BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
416331ca
XL
735 }
736 }
737
738 pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
739 match *self {
740 BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
741 BorrowedContentSource::DerefSharedRef => Some("shared reference"),
742 BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
743 // Overloaded deref and index operators should be evaluated into a
744 // temporary. So we don't need a description here.
745 BorrowedContentSource::OverloadedDeref(_)
dfeec247 746 | BorrowedContentSource::OverloadedIndex(_) => None,
416331ca
XL
747 }
748 }
749
ba9703b0 750 pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
416331ca 751 match *self {
74b04a01
XL
752 BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
753 BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
416331ca 754 BorrowedContentSource::DerefMutableRef => {
dfeec247
XL
755 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
756 }
a2a8927a
XL
757 BorrowedContentSource::OverloadedDeref(ty) => ty
758 .ty_adt_def()
5e7ed085 759 .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
9c376795 760 name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
a2a8927a
XL
761 _ => None,
762 })
9c376795
FG
763 .unwrap_or_else(|| format!("dereference of `{ty}`")),
764 BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
416331ca
XL
765 }
766 }
767
768 fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
1b1a35ee 769 match *func.kind() {
416331ca
XL
770 ty::FnDef(def_id, substs) => {
771 let trait_id = tcx.trait_of_item(def_id)?;
772
773 let lang_items = tcx.lang_items();
774 if Some(trait_id) == lang_items.deref_trait()
775 || Some(trait_id) == lang_items.deref_mut_trait()
776 {
777 Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
778 } else if Some(trait_id) == lang_items.index_trait()
779 || Some(trait_id) == lang_items.index_mut_trait()
780 {
781 Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
782 } else {
783 None
784 }
785 }
786 _ => None,
787 }
788 }
789}
790
dc9dc135 791impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
b7449926
XL
792 /// Finds the spans associated to a move or copy of move_place at location.
793 pub(super) fn move_spans(
794 &self,
74b04a01 795 moved_place: PlaceRef<'tcx>, // Could also be an upvar.
b7449926 796 location: Location,
1b1a35ee 797 ) -> UseSpans<'tcx> {
b7449926 798 use self::UseSpans::*;
b7449926 799
5e7ed085
FG
800 let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {
801 return OtherUse(self.body.source_info(location).span);
b7449926
XL
802 };
803
0bf4aa26 804 debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
487cf647
FG
805 if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
806 && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind
807 {
808 debug!("move_spans: def_id={:?} places={:?}", def_id, places);
9ffffee4 809 let def_id = def_id.expect_local();
487cf647
FG
810 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
811 self.closure_span(def_id, moved_place, places)
812 {
813 return ClosureUse {
814 generator_kind,
815 args_span,
816 capture_kind_span,
817 path_span,
818 };
f035d41b
XL
819 }
820 }
821
cdc7bbd5
XL
822 // StatementKind::FakeRead only contains a def_id if they are introduced as a result
823 // of pattern matching within a closure.
487cf647 824 if let StatementKind::FakeRead(box (cause, place)) = stmt.kind {
cdc7bbd5
XL
825 match cause {
826 FakeReadCause::ForMatchedPlace(Some(closure_def_id))
827 | FakeReadCause::ForLet(Some(closure_def_id)) => {
828 debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
487cf647 829 let places = &[Operand::Move(place)];
17df50a5 830 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
353b0b11 831 self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
cdc7bbd5 832 {
17df50a5
XL
833 return ClosureUse {
834 generator_kind,
835 args_span,
836 capture_kind_span,
837 path_span,
838 };
cdc7bbd5
XL
839 }
840 }
841 _ => {}
842 }
843 }
844
f035d41b
XL
845 let normal_ret =
846 if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
847 PatUse(stmt.source_info.span)
848 } else {
849 OtherUse(stmt.source_info.span)
0bf4aa26
XL
850 };
851
f035d41b
XL
852 // We are trying to find MIR of the form:
853 // ```
854 // _temp = _moved_val;
855 // ...
856 // FnSelfCall(_temp, ...)
857 // ```
858 //
859 // where `_moved_val` is the place we generated the move error for,
860 // `_temp` is some other local, and `FnSelfCall` is a function
861 // that has a `self` parameter.
862
863 let target_temp = match stmt.kind {
864 StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
865 temp.as_local().unwrap()
b7449926 866 }
f035d41b
XL
867 _ => return normal_ret,
868 };
b7449926 869
f035d41b
XL
870 debug!("move_spans: target_temp = {:?}", target_temp);
871
872 if let Some(Terminator {
1b1a35ee 873 kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
f035d41b
XL
874 }) = &self.body[location.block].terminator
875 {
5099ac24 876 let Some((method_did, method_substs)) =
c295e0f8
XL
877 rustc_const_eval::util::find_self_call(
878 self.infcx.tcx,
879 &self.body,
880 target_temp,
881 location.block,
5099ac24
FG
882 )
883 else {
1b1a35ee
XL
884 return normal_ret;
885 };
f035d41b 886
5099ac24
FG
887 let kind = call_kind(
888 self.infcx.tcx,
889 self.param_env,
890 method_did,
891 method_substs,
892 *fn_span,
893 *from_hir_call,
894 Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
1b1a35ee
XL
895 );
896
1b1a35ee
XL
897 return FnSelfUse {
898 var_span: stmt.source_info.span,
5099ac24 899 fn_call_span: *fn_span,
064997fb 900 fn_span: self.infcx.tcx.def_span(method_did),
1b1a35ee
XL
901 kind,
902 };
f035d41b 903 }
3dfed10e 904 normal_ret
b7449926
XL
905 }
906
907 /// Finds the span of arguments of a closure (within `maybe_closure_span`)
908 /// and its usage of the local assigned at `location`.
909 /// This is done by searching in statements succeeding `location`
910 /// and originating from `maybe_closure_span`.
1b1a35ee 911 pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
b7449926 912 use self::UseSpans::*;
0bf4aa26 913 debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
b7449926 914
dfeec247 915 let target = match self.body[location.block].statements.get(location.statement_index) {
487cf647 916 Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
e74abb32
XL
917 if let Some(local) = place.as_local() {
918 local
919 } else {
920 return OtherUse(use_span);
921 }
922 }
b7449926
XL
923 _ => return OtherUse(use_span),
924 };
925
dc9dc135 926 if self.body.local_kind(target) != LocalKind::Temp {
b7449926
XL
927 // operands are always temporaries.
928 return OtherUse(use_span);
929 }
930
353b0b11
FG
931 // drop and replace might have moved the assignment to the next block
932 let maybe_additional_statement =
933 if let TerminatorKind::Drop { target: drop_target, .. } =
934 self.body[location.block].terminator().kind
935 {
936 self.body[drop_target].statements.first()
937 } else {
938 None
939 };
940
941 let statements =
942 self.body[location.block].statements[location.statement_index + 1..].iter();
943
944 for stmt in statements.chain(maybe_additional_statement) {
487cf647 945 if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
064997fb 946 let (&def_id, is_generator) = match kind {
0bf4aa26
XL
947 box AggregateKind::Closure(def_id, _) => (def_id, false),
948 box AggregateKind::Generator(def_id, _, _) => (def_id, true),
949 _ => continue,
950 };
9ffffee4 951 let def_id = def_id.expect_local();
b7449926 952
0bf4aa26
XL
953 debug!(
954 "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
955 def_id, is_generator, places
956 );
17df50a5 957 if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
064997fb 958 self.closure_span(def_id, Place::from(target).as_ref(), places)
dfeec247 959 {
17df50a5 960 return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
0bf4aa26
XL
961 } else {
962 return OtherUse(use_span);
b7449926
XL
963 }
964 }
965
966 if use_span != stmt.source_info.span {
967 break;
968 }
969 }
970
971 OtherUse(use_span)
972 }
973
17df50a5
XL
974 /// Finds the spans of a captured place within a closure or generator.
975 /// The first span is the location of the use resulting in the capture kind of the capture
976 /// The second span is the location the use resulting in the captured path of the capture
0bf4aa26
XL
977 fn closure_span(
978 &self,
064997fb 979 def_id: LocalDefId,
74b04a01 980 target_place: PlaceRef<'tcx>,
353b0b11 981 places: &IndexSlice<FieldIdx, Operand<'tcx>>,
17df50a5 982 ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
0bf4aa26
XL
983 debug!(
984 "closure_span: def_id={:?} target_place={:?} places={:?}",
985 def_id, target_place, places
986 );
064997fb 987 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(def_id);
e74abb32 988 let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
532ac7d7 989 debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
064997fb
FG
990 if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
991 for (captured_place, place) in
9ffffee4 992 self.infcx.tcx.closure_captures(def_id).iter().zip(places)
17df50a5 993 {
48663c56 994 match place {
dfeec247
XL
995 Operand::Copy(place) | Operand::Move(place)
996 if target_place == place.as_ref() =>
997 {
48663c56 998 debug!("closure_span: found captured local {:?}", place);
064997fb 999 let body = self.infcx.tcx.hir().body(body);
e74abb32 1000 let generator_kind = body.generator_kind();
1b1a35ee 1001
17df50a5 1002 return Some((
064997fb 1003 fn_decl_span,
17df50a5
XL
1004 generator_kind,
1005 captured_place.get_capture_kind_span(self.infcx.tcx),
1006 captured_place.get_path_span(self.infcx.tcx),
1007 ));
dfeec247 1008 }
48663c56
XL
1009 _ => {}
1010 }
1011 }
0bf4aa26 1012 }
48663c56 1013 None
0bf4aa26
XL
1014 }
1015
b7449926
XL
1016 /// Helper to retrieve span(s) of given borrow from the current MIR
1017 /// representation
1b1a35ee 1018 pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
dc9dc135 1019 let span = self.body.source_info(borrow.reserve_location).span;
b7449926
XL
1020 self.borrow_spans(span, borrow.reserve_location)
1021 }
5e7ed085
FG
1022
1023 fn explain_captures(
1024 &mut self,
1025 err: &mut Diagnostic,
1026 span: Span,
1027 move_span: Span,
1028 move_spans: UseSpans<'tcx>,
1029 moved_place: Place<'tcx>,
5e7ed085
FG
1030 partially_str: &str,
1031 loop_message: &str,
1032 move_msg: &str,
1033 is_loop_move: bool,
1034 maybe_reinitialized_locations_is_empty: bool,
1035 ) {
1036 if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
1037 let place_name = self
1038 .describe_place(moved_place.as_ref())
9c376795 1039 .map(|n| format!("`{n}`"))
5e7ed085
FG
1040 .unwrap_or_else(|| "value".to_owned());
1041 match kind {
1042 CallKind::FnCall { fn_trait_id, .. }
1043 if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
1044 {
1045 err.span_label(
1046 fn_call_span,
1047 &format!(
9c376795 1048 "{place_name} {partially_str}moved due to this call{loop_message}",
5e7ed085
FG
1049 ),
1050 );
1051 err.span_note(
1052 var_span,
1053 "this value implements `FnOnce`, which causes it to be moved when called",
1054 );
1055 }
1056 CallKind::Operator { self_arg, .. } => {
1057 let self_arg = self_arg.unwrap();
1058 err.span_label(
1059 fn_call_span,
1060 &format!(
9c376795 1061 "{place_name} {partially_str}moved due to usage in operator{loop_message}",
5e7ed085
FG
1062 ),
1063 );
1064 if self.fn_self_span_reported.insert(fn_span) {
1065 err.span_note(
9c376795 1066 self_arg.span,
5e7ed085
FG
1067 "calling this operator moves the left-hand side",
1068 );
1069 }
1070 }
9ffffee4 1071 CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
5e7ed085 1072 let self_arg = self_arg.unwrap();
9c376795 1073 let tcx = self.infcx.tcx;
5e7ed085 1074 if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
9c376795
FG
1075 let ty = moved_place.ty(self.body, tcx).ty;
1076 let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
2b03887a
FG
1077 Some(def_id) => {
1078 let infcx = self.infcx.tcx.infer_ctxt().build();
5e7ed085
FG
1079 type_known_to_meet_bound_modulo_regions(
1080 &infcx,
1081 self.param_env,
9c376795 1082 tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
5e7ed085 1083 def_id,
5e7ed085 1084 )
2b03887a 1085 }
5e7ed085
FG
1086 _ => false,
1087 };
1088 if suggest {
1089 err.span_suggestion_verbose(
1090 move_span.shrink_to_lo(),
1091 &format!(
9c376795 1092 "consider iterating over a slice of the `{ty}`'s content to \
5e7ed085 1093 avoid moving into the `for` loop",
5e7ed085 1094 ),
923072b8 1095 "&",
5e7ed085
FG
1096 Applicability::MaybeIncorrect,
1097 );
1098 }
1099
1100 err.span_label(
1101 fn_call_span,
1102 &format!(
9c376795 1103 "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
5e7ed085
FG
1104 ),
1105 );
2b03887a
FG
1106 // If the moved place was a `&mut` ref, then we can
1107 // suggest to reborrow it where it was moved, so it
1108 // will still be valid by the time we get to the usage.
1109 if let ty::Ref(_, _, hir::Mutability::Mut) =
1110 moved_place.ty(self.body, self.infcx.tcx).ty.kind()
5e7ed085
FG
1111 {
1112 // If we are in a loop this will be suggested later.
1113 if !is_loop_move {
1114 err.span_suggestion_verbose(
1115 move_span.shrink_to_lo(),
1116 &format!(
1117 "consider creating a fresh reborrow of {} here",
1118 self.describe_place(moved_place.as_ref())
9c376795 1119 .map(|n| format!("`{n}`"))
5e7ed085
FG
1120 .unwrap_or_else(|| "the mutable reference".to_string()),
1121 ),
923072b8 1122 "&mut *",
5e7ed085
FG
1123 Applicability::MachineApplicable,
1124 );
1125 }
1126 }
1127 } else {
1128 err.span_label(
1129 fn_call_span,
1130 &format!(
9c376795 1131 "{place_name} {partially_str}moved due to this method call{loop_message}",
5e7ed085
FG
1132 ),
1133 );
9ffffee4 1134
9c376795 1135 let infcx = tcx.infer_ctxt().build();
9ffffee4 1136 // Erase and shadow everything that could be passed to the new infcx.
9c376795 1137 let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
9ffffee4
FG
1138 let method_substs = tcx.erase_regions(method_substs);
1139
9c376795
FG
1140 if let ty::Adt(def, substs) = ty.kind()
1141 && Some(def.did()) == tcx.lang_items().pin_type()
1142 && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
9ffffee4 1143 && let self_ty = infcx.instantiate_binder_with_fresh_vars(
9c376795
FG
1144 fn_call_span,
1145 LateBoundRegionConversionTime::FnCall,
9ffffee4 1146 tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
9c376795 1147 )
9ffffee4 1148 && infcx.can_eq(self.param_env, ty, self_ty)
9c376795
FG
1149 {
1150 err.span_suggestion_verbose(
1151 fn_call_span.shrink_to_lo(),
1152 "consider reborrowing the `Pin` instead of moving it",
1153 "as_mut().".to_string(),
1154 Applicability::MaybeIncorrect,
1155 );
1156 }
1157 if let Some(clone_trait) = tcx.lang_items().clone_trait()
1158 && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
1159 && let o = Obligation::new(
1160 tcx,
1161 ObligationCause::dummy(),
1162 self.param_env,
1163 ty::Binder::dummy(trait_ref),
1164 )
1165 && infcx.predicate_must_hold_modulo_regions(&o)
1166 {
1167 err.span_suggestion_verbose(
1168 fn_call_span.shrink_to_lo(),
1169 "you can `clone` the value and consume it, but this might not be \
1170 your desired behavior",
1171 "clone().".to_string(),
1172 Applicability::MaybeIncorrect,
1173 );
1174 }
5e7ed085 1175 }
5e7ed085
FG
1176 // Avoid pointing to the same function in multiple different
1177 // error messages.
1178 if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
9c376795 1179 let func = tcx.def_path_str(method_did);
5e7ed085
FG
1180 err.span_note(
1181 self_arg.span,
9c376795 1182 &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
5e7ed085
FG
1183 );
1184 }
9c376795 1185 let parent_did = tcx.parent(method_did);
9ffffee4
FG
1186 let parent_self_ty =
1187 matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
1188 .then_some(parent_did)
1189 .and_then(|did| match tcx.type_of(did).subst_identity().kind() {
1190 ty::Adt(def, ..) => Some(def.did()),
1191 _ => None,
1192 });
9c376795
FG
1193 let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
1194 matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
1195 });
f2b60f7d
FG
1196 if is_option_or_result && maybe_reinitialized_locations_is_empty {
1197 err.span_label(
1198 var_span,
1199 "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
1200 );
1201 }
5e7ed085
FG
1202 }
1203 // Other desugarings takes &self, which cannot cause a move
1204 _ => {}
1205 }
1206 } else {
1207 if move_span != span || !loop_message.is_empty() {
1208 err.span_label(
1209 move_span,
9c376795 1210 format!("value {partially_str}moved{move_msg} here{loop_message}"),
5e7ed085
FG
1211 );
1212 }
1213 // If the move error occurs due to a loop, don't show
1214 // another message for the same span
1215 if loop_message.is_empty() {
1216 move_spans.var_span_label(
1217 err,
9c376795 1218 format!("variable {partially_str}moved due to use{}", move_spans.describe()),
5e7ed085
FG
1219 "moved",
1220 );
1221 }
1222 }
1223 }
ff7c6d11 1224}