]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_mir / src / borrow_check / diagnostics / mod.rs
CommitLineData
60c5eb7d
XL
1//! Borrow checker diagnostics.
2
dc9dc135 3use rustc_errors::DiagnosticBuilder;
dfeec247
XL
4use rustc_hir as hir;
5use rustc_hir::def::Namespace;
6use rustc_hir::def_id::DefId;
f035d41b 7use rustc_hir::lang_items::LangItemGroup;
dfeec247 8use rustc_hir::GeneratorKind;
ba9703b0
XL
9use rustc_middle::mir::{
10 AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
11 PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
12};
13use rustc_middle::ty::print::Print;
1b1a35ee 14use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
f035d41b
XL
15use rustc_span::{
16 hygiene::{DesugaringKind, ForLoopLoc},
17 symbol::sym,
18 Span,
19};
ba9703b0 20use rustc_target::abi::VariantIdx;
ff7c6d11 21
94b46f34 22use super::borrow_set::BorrowData;
e74abb32 23use super::MirBorrowckCtxt;
416331ca 24use crate::dataflow::move_paths::{InitLocation, LookupResult};
ff7c6d11 25
60c5eb7d 26mod find_use;
60c5eb7d 27mod outlives_suggestion;
dfeec247
XL
28mod region_name;
29mod var_name;
60c5eb7d
XL
30
31mod conflict_errors;
dfeec247 32mod explain_borrow;
60c5eb7d
XL
33mod move_errors;
34mod mutability_errors;
35mod region_errors;
60c5eb7d
XL
36
37crate use mutability_errors::AccessKind;
60c5eb7d 38crate use outlives_suggestion::OutlivesSuggestionBuilder;
dfeec247
XL
39crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
40crate use region_name::{RegionName, RegionNameSource};
f035d41b 41use rustc_span::symbol::Ident;
60c5eb7d 42
dc9dc135 43pub(super) struct IncludingDowncast(pub(super) bool);
0bf4aa26 44
dc9dc135 45impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
0731742a
XL
46 /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
47 /// is moved after being invoked.
0bf4aa26
XL
48 ///
49 /// ```text
50 /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
51 /// its environment
52 /// --> $DIR/issue-42065.rs:16:29
53 /// |
54 /// LL | for (key, value) in dict {
55 /// | ^^^^
56 /// ```
0731742a 57 pub(super) fn add_moved_or_invoked_closure_note(
0bf4aa26
XL
58 &self,
59 location: Location,
74b04a01 60 place: PlaceRef<'tcx>,
0bf4aa26
XL
61 diag: &mut DiagnosticBuilder<'_>,
62 ) {
0731742a 63 debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
dc9dc135
XL
64 let mut target = place.local_or_deref_local();
65 for stmt in &self.body[location.block].statements[location.statement_index..] {
0731742a 66 debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
dfeec247 67 if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
0731742a 68 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
0bf4aa26 69 match from {
dfeec247
XL
70 Operand::Copy(ref place) | Operand::Move(ref place)
71 if target == place.local_or_deref_local() =>
72 {
73 target = into.local_or_deref_local()
74 }
75 _ => {}
0bf4aa26
XL
76 }
77 }
78 }
79
0731742a 80 // Check if we are attempting to call a closure after it has been invoked.
dc9dc135 81 let terminator = self.body[location.block].terminator();
0731742a 82 debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
0bf4aa26 83 if let TerminatorKind::Call {
6a06907d 84 func: Operand::Constant(box Constant { literal, .. }),
0bf4aa26
XL
85 args,
86 ..
dfeec247
XL
87 } = &terminator.kind
88 {
6a06907d 89 if let ty::FnDef(id, _) = *literal.ty().kind() {
1b1a35ee
XL
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() =>
95 {
96 place.local_or_deref_local().unwrap()
97 }
98 _ => return,
99 };
0bf4aa26 100
1b1a35ee
XL
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);
0bf4aa26 105
5869c6ff 106 if let Some((span, hir_place)) =
1b1a35ee
XL
107 self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
108 {
109 diag.span_note(
110 *span,
111 &format!(
112 "closure cannot be invoked more than once because it moves the \
113 variable `{}` out of its environment",
5869c6ff 114 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
1b1a35ee
XL
115 ),
116 );
117 return;
118 }
0bf4aa26
XL
119 }
120 }
121 }
122 }
0731742a
XL
123
124 // Check if we are just moving a closure after it has been invoked.
125 if let Some(target) = target {
1b1a35ee 126 if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
f9f354fc 127 let did = did.expect_local();
3dfed10e 128 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
0731742a 129
5869c6ff 130 if let Some((span, hir_place)) =
3dfed10e 131 self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
0731742a
XL
132 {
133 diag.span_note(
134 *span,
135 &format!(
136 "closure cannot be moved more than once as it is not `Copy` due to \
137 moving the variable `{}` out of its environment",
5869c6ff 138 ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
0731742a
XL
139 ),
140 );
141 }
142 }
143 }
0bf4aa26
XL
144 }
145
ba9703b0
XL
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) {
150 Some(mut descr) => {
151 // Surround descr with `backticks`.
152 descr.reserve(2);
1b1a35ee
XL
153 descr.insert(0, '`');
154 descr.push('`');
ba9703b0
XL
155 descr
156 }
157 None => "value".to_string(),
158 }
159 }
160
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.
74b04a01 163 pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
416331ca 164 self.describe_place_with_options(place_ref, IncludingDowncast(false))
8faf50e0
XL
165 }
166
0bf4aa26
XL
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
8faf50e0
XL
171 pub(super) fn describe_place_with_options(
172 &self,
74b04a01 173 place: PlaceRef<'tcx>,
8faf50e0
XL
174 including_downcast: IncludingDowncast,
175 ) -> Option<String> {
ff7c6d11 176 let mut buf = String::new();
8faf50e0 177 match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
ff7c6d11
XL
178 Ok(()) => Some(buf),
179 Err(()) => None,
180 }
181 }
182
0bf4aa26 183 /// Appends end-user visible description of `place` to `buf`.
ff7c6d11
XL
184 fn append_place_to_string(
185 &self,
74b04a01 186 place: PlaceRef<'tcx>,
ff7c6d11
XL
187 buf: &mut String,
188 mut autoderef: bool,
8faf50e0 189 including_downcast: &IncludingDowncast,
ff7c6d11 190 ) -> Result<(), ()> {
416331ca 191 match place {
dfeec247 192 PlaceRef { local, projection: [] } => {
74b04a01 193 self.append_local_to_string(local, buf)?;
ff7c6d11 194 }
dfeec247 195 PlaceRef { local, projection: [ProjectionElem::Deref] }
74b04a01 196 if self.body.local_decls[local].is_ref_for_guard() =>
dfeec247 197 {
60c5eb7d 198 self.append_place_to_string(
74b04a01 199 PlaceRef { local, projection: &[] },
60c5eb7d
XL
200 buf,
201 autoderef,
202 &including_downcast,
203 )?;
dfeec247
XL
204 }
205 PlaceRef { local, projection: [ProjectionElem::Deref] }
74b04a01 206 if self.body.local_decls[local].is_ref_to_static() =>
dfeec247 207 {
74b04a01 208 let local_info = &self.body.local_decls[local].local_info;
f9f354fc 209 if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
60c5eb7d
XL
210 buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
211 } else {
212 unreachable!();
213 }
dfeec247
XL
214 }
215 PlaceRef { local, projection: [proj_base @ .., elem] } => {
e1599b0c 216 match elem {
ff7c6d11 217 ProjectionElem::Deref => {
5869c6ff 218 // FIXME(project-rfc_2229#36): print capture precisely here.
dfeec247 219 let upvar_field_projection = self.is_upvar_field_projection(place);
8faf50e0 220 if let Some(field) = upvar_field_projection {
ff7c6d11 221 let var_index = field.index();
48663c56
XL
222 let name = self.upvars[var_index].name.to_string();
223 if self.upvars[var_index].by_ref {
ff7c6d11
XL
224 buf.push_str(&name);
225 } else {
1b1a35ee
XL
226 buf.push('*');
227 buf.push_str(&name);
ff7c6d11
XL
228 }
229 } else {
230 if autoderef {
416331ca 231 // FIXME turn this recursion into iteration
8faf50e0 232 self.append_place_to_string(
dfeec247 233 PlaceRef { local, projection: proj_base },
8faf50e0
XL
234 buf,
235 autoderef,
236 &including_downcast,
237 )?;
ff7c6d11 238 } else {
1b1a35ee 239 buf.push('*');
dfeec247
XL
240 self.append_place_to_string(
241 PlaceRef { local, projection: proj_base },
242 buf,
243 autoderef,
244 &including_downcast,
245 )?;
ff7c6d11
XL
246 }
247 }
248 }
249 ProjectionElem::Downcast(..) => {
8faf50e0 250 self.append_place_to_string(
dfeec247 251 PlaceRef { local, projection: proj_base },
8faf50e0
XL
252 buf,
253 autoderef,
254 &including_downcast,
255 )?;
256 if including_downcast.0 {
257 return Err(());
258 }
ff7c6d11
XL
259 }
260 ProjectionElem::Field(field, _ty) => {
261 autoderef = true;
262
5869c6ff 263 // FIXME(project-rfc_2229#36): print capture precisely here.
dfeec247 264 let upvar_field_projection = self.is_upvar_field_projection(place);
8faf50e0 265 if let Some(field) = upvar_field_projection {
ff7c6d11 266 let var_index = field.index();
48663c56 267 let name = self.upvars[var_index].name.to_string();
ff7c6d11
XL
268 buf.push_str(&name);
269 } else {
dfeec247
XL
270 let field_name = self
271 .describe_field(PlaceRef { local, projection: proj_base }, *field);
8faf50e0 272 self.append_place_to_string(
dfeec247 273 PlaceRef { local, projection: proj_base },
8faf50e0
XL
274 buf,
275 autoderef,
276 &including_downcast,
277 )?;
1b1a35ee
XL
278 buf.push('.');
279 buf.push_str(&field_name);
ff7c6d11
XL
280 }
281 }
282 ProjectionElem::Index(index) => {
283 autoderef = true;
284
8faf50e0 285 self.append_place_to_string(
dfeec247 286 PlaceRef { local, projection: proj_base },
8faf50e0
XL
287 buf,
288 autoderef,
289 &including_downcast,
290 )?;
1b1a35ee 291 buf.push('[');
e1599b0c 292 if self.append_local_to_string(*index, buf).is_err() {
1b1a35ee 293 buf.push('_');
ff7c6d11 294 }
1b1a35ee 295 buf.push(']');
ff7c6d11
XL
296 }
297 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
298 autoderef = true;
299 // Since it isn't possible to borrow an element on a particular index and
300 // then use another while the borrow is held, don't output indices details
301 // to avoid confusing the end-user
8faf50e0 302 self.append_place_to_string(
dfeec247 303 PlaceRef { local, projection: proj_base },
8faf50e0
XL
304 buf,
305 autoderef,
306 &including_downcast,
307 )?;
1b1a35ee 308 buf.push_str("[..]");
ff7c6d11
XL
309 }
310 };
311 }
312 }
313
314 Ok(())
315 }
316
0bf4aa26 317 /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
dc9dc135 318 /// a name, or its name was generated by the compiler, then `Err` is returned
60c5eb7d
XL
319 fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
320 let decl = &self.body.local_decls[local];
321 match self.local_names[local] {
322 Some(name) if !decl.from_compiler_desugaring() => {
e1599b0c 323 buf.push_str(&name.as_str());
ff7c6d11
XL
324 Ok(())
325 }
dc9dc135 326 _ => Err(()),
ff7c6d11
XL
327 }
328 }
329
0bf4aa26 330 /// End-user visible description of the `field`nth field of `base`
74b04a01 331 fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
416331ca
XL
332 // FIXME Place2 Make this work iteratively
333 match place {
dfeec247 334 PlaceRef { local, projection: [] } => {
74b04a01 335 let local = &self.body.local_decls[local];
532ac7d7 336 self.describe_field_from_ty(&local.ty, field, None)
ff7c6d11 337 }
dfeec247 338 PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
e1599b0c 339 ProjectionElem::Deref => {
dfeec247 340 self.describe_field(PlaceRef { local, projection: proj_base }, field)
e1599b0c 341 }
532ac7d7 342 ProjectionElem::Downcast(_, variant_index) => {
5869c6ff 343 let base_ty = place.ty(self.body, self.infcx.tcx).ty;
e1599b0c 344 self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
532ac7d7 345 }
ff7c6d11 346 ProjectionElem::Field(_, field_type) => {
532ac7d7 347 self.describe_field_from_ty(&field_type, field, None)
ff7c6d11 348 }
0531ce1d
XL
349 ProjectionElem::Index(..)
350 | ProjectionElem::ConstantIndex { .. }
351 | ProjectionElem::Subslice { .. } => {
dfeec247 352 self.describe_field(PlaceRef { local, projection: proj_base }, field)
ff7c6d11
XL
353 }
354 },
355 }
356 }
357
0bf4aa26 358 /// End-user visible description of the `field_index`nth field of `ty`
532ac7d7
XL
359 fn describe_field_from_ty(
360 &self,
48663c56 361 ty: Ty<'_>,
532ac7d7 362 field: Field,
dfeec247 363 variant_index: Option<VariantIdx>,
532ac7d7 364 ) -> String {
ff7c6d11
XL
365 if ty.is_box() {
366 // If the type is a box, the field is described from the boxed type
532ac7d7 367 self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
ff7c6d11 368 } else {
1b1a35ee 369 match *ty.kind() {
532ac7d7
XL
370 ty::Adt(def, _) => {
371 let variant = if let Some(idx) = variant_index {
372 assert!(def.is_enum());
373 &def.variants[idx]
374 } else {
375 def.non_enum_variant()
376 };
dfeec247
XL
377 variant.fields[field.index()].ident.to_string()
378 }
b7449926
XL
379 ty::Tuple(_) => field.index().to_string(),
380 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
532ac7d7 381 self.describe_field_from_ty(&ty, field, variant_index)
ff7c6d11 382 }
dfeec247
XL
383 ty::Array(ty, _) | ty::Slice(ty) => {
384 self.describe_field_from_ty(&ty, field, variant_index)
385 }
b7449926 386 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
fc512014
XL
387 // We won't be borrowck'ing here if the closure came from another crate,
388 // so it's safe to call `expect_local`.
389 //
390 // We know the field exists so it's safe to call operator[] and `unwrap` here.
6a06907d
XL
391 let var_id = self
392 .infcx
393 .tcx
394 .typeck(def_id.expect_local())
395 .closure_min_captures_flattened(def_id)
396 .nth(field.index())
397 .unwrap()
398 .get_root_variable();
ff7c6d11 399
dc9dc135 400 self.infcx.tcx.hir().name(var_id).to_string()
ff7c6d11
XL
401 }
402 _ => {
403 // Might need a revision when the fields in trait RFC is implemented
404 // (https://github.com/rust-lang/rfcs/pull/1546)
dfeec247 405 bug!("End-user description not implemented for field access on `{:?}`", ty);
ff7c6d11
XL
406 }
407 }
408 }
409 }
410
dc9dc135
XL
411 /// Add a note that a type does not implement `Copy`
412 pub(super) fn note_type_does_not_implement_copy(
0bf4aa26 413 &self,
dc9dc135
XL
414 err: &mut DiagnosticBuilder<'a>,
415 place_desc: &str,
416 ty: Ty<'tcx>,
417 span: Option<Span>,
1b1a35ee 418 move_prefix: &str,
dc9dc135
XL
419 ) {
420 let message = format!(
1b1a35ee
XL
421 "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
422 move_prefix, place_desc, ty,
0bf4aa26 423 );
dc9dc135
XL
424 if let Some(span) = span {
425 err.span_label(span, message);
426 } else {
427 err.note(&message);
0bf4aa26
XL
428 }
429 }
416331ca
XL
430
431 pub(super) fn borrowed_content_source(
432 &self,
74b04a01 433 deref_base: PlaceRef<'tcx>,
416331ca
XL
434 ) -> BorrowedContentSource<'tcx> {
435 let tcx = self.infcx.tcx;
436
437 // Look up the provided place and work out the move path index for it,
438 // we'll use this to check whether it was originally from an overloaded
439 // operator.
440 match self.move_data.rev_lookup.find(deref_base) {
441 LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
442 debug!("borrowed_content_source: mpi={:?}", mpi);
443
444 for i in &self.move_data.init_path_map[mpi] {
445 let init = &self.move_data.inits[*i];
446 debug!("borrowed_content_source: init={:?}", init);
447 // We're only interested in statements that initialized a value, not the
448 // initializations from arguments.
449 let loc = match init.location {
450 InitLocation::Statement(stmt) => stmt,
451 _ => continue,
452 };
453
454 let bbd = &self.body[loc.block];
455 let is_terminator = bbd.statements.len() == loc.statement_index;
456 debug!(
457 "borrowed_content_source: loc={:?} is_terminator={:?}",
dfeec247 458 loc, is_terminator,
416331ca
XL
459 );
460 if !is_terminator {
461 continue;
462 } else if let Some(Terminator {
dfeec247 463 kind: TerminatorKind::Call { ref func, from_hir_call: false, .. },
416331ca 464 ..
dfeec247
XL
465 }) = bbd.terminator
466 {
467 if let Some(source) =
f9f354fc 468 BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
dfeec247 469 {
416331ca
XL
470 return source;
471 }
472 }
473 }
474 }
475 // Base is a `static` so won't be from an overloaded operator
476 _ => (),
477 };
478
479 // If we didn't find an overloaded deref or index, then assume it's a
480 // built in deref and check the type of the base.
5869c6ff 481 let base_ty = deref_base.ty(self.body, tcx).ty;
416331ca
XL
482 if base_ty.is_unsafe_ptr() {
483 BorrowedContentSource::DerefRawPointer
484 } else if base_ty.is_mutable_ptr() {
485 BorrowedContentSource::DerefMutableRef
486 } else {
487 BorrowedContentSource::DerefSharedRef
488 }
489 }
532ac7d7 490}
0bf4aa26 491
dc9dc135 492impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
0bf4aa26
XL
493 /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
494 /// name where required.
dc9dc135 495 pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
532ac7d7
XL
496 let mut s = String::new();
497 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
498
0bf4aa26
XL
499 // We need to add synthesized lifetimes where appropriate. We do
500 // this by hooking into the pretty printer and telling it to label the
501 // lifetimes without names with the value `'0`.
1b1a35ee 502 match ty.kind() {
ba9703b0 503 ty::Ref(
fc512014 504 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br })
ba9703b0 505 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
0bf4aa26
XL
506 _,
507 _,
532ac7d7
XL
508 ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
509 _ => {}
0bf4aa26 510 }
532ac7d7
XL
511
512 let _ = ty.print(printer);
513 s
0bf4aa26
XL
514 }
515
9fa01778 516 /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
0bf4aa26 517 /// synthesized lifetime name where required.
dc9dc135 518 pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
532ac7d7
XL
519 let mut s = String::new();
520 let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
521
1b1a35ee 522 let region = match ty.kind() {
532ac7d7
XL
523 ty::Ref(region, _, _) => {
524 match region {
fc512014 525 ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br })
532ac7d7
XL
526 | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
527 printer.region_highlight_mode.highlighting_bound_region(*br, counter)
528 }
529 _ => {}
0bf4aa26 530 }
532ac7d7
XL
531
532 region
533 }
0bf4aa26 534 _ => bug!("ty for annotation of borrow region is not a reference"),
532ac7d7
XL
535 };
536
537 let _ = region.print(printer);
538 s
0bf4aa26 539 }
b7449926
XL
540}
541
f035d41b 542/// The span(s) associated to a use of a place.
b7449926 543#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1b1a35ee 544pub(super) enum UseSpans<'tcx> {
f035d41b 545 /// The access is caused by capturing a variable for a closure.
b7449926 546 ClosureUse {
f035d41b 547 /// This is true if the captured variable was from a generator.
e74abb32 548 generator_kind: Option<GeneratorKind>,
f035d41b
XL
549 /// The span of the args of the closure, including the `move` keyword if
550 /// it's present.
b7449926 551 args_span: Span,
f035d41b
XL
552 /// The span of the first use of the captured variable inside the closure.
553 var_span: Span,
554 },
555 /// The access is caused by using a variable as the receiver of a method
556 /// that takes 'self'
557 FnSelfUse {
558 /// The span of the variable being moved
b7449926 559 var_span: Span,
f035d41b
XL
560 /// The span of the method call on the variable
561 fn_call_span: Span,
562 /// The definition span of the method being called
563 fn_span: Span,
1b1a35ee 564 kind: FnSelfUseKind<'tcx>,
b7449926 565 },
f035d41b
XL
566 /// This access is caused by a `match` or `if let` pattern.
567 PatUse(Span),
568 /// This access has a single span associated to it: common case.
b7449926
XL
569 OtherUse(Span),
570}
571
f035d41b 572#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1b1a35ee 573pub(super) enum FnSelfUseKind<'tcx> {
f035d41b
XL
574 /// A normal method call of the form `receiver.foo(a, b, c)`
575 Normal { self_arg: Ident, implicit_into_iter: bool },
576 /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
577 FnOnceCall,
578 /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
579 Operator { self_arg: Ident },
1b1a35ee
XL
580 DerefCoercion {
581 /// The `Span` of the `Target` associated type
582 /// in the `Deref` impl we are using.
583 deref_target: Span,
584 /// The type `T::Deref` we are dereferencing to
585 deref_target_ty: Ty<'tcx>,
586 },
f035d41b
XL
587}
588
1b1a35ee 589impl UseSpans<'_> {
b7449926
XL
590 pub(super) fn args_or_use(self) -> Span {
591 match self {
f035d41b
XL
592 UseSpans::ClosureUse { args_span: span, .. }
593 | UseSpans::PatUse(span)
f035d41b 594 | UseSpans::OtherUse(span) => span,
1b1a35ee
XL
595 UseSpans::FnSelfUse {
596 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
597 } => fn_call_span,
598 UseSpans::FnSelfUse { var_span, .. } => var_span,
b7449926
XL
599 }
600 }
601
602 pub(super) fn var_or_use(self) -> Span {
603 match self {
f035d41b
XL
604 UseSpans::ClosureUse { var_span: span, .. }
605 | UseSpans::PatUse(span)
f035d41b 606 | UseSpans::OtherUse(span) => span,
1b1a35ee
XL
607 UseSpans::FnSelfUse {
608 fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
609 } => fn_call_span,
610 UseSpans::FnSelfUse { var_span, .. } => var_span,
b7449926
XL
611 }
612 }
613
e74abb32
XL
614 pub(super) fn generator_kind(self) -> Option<GeneratorKind> {
615 match self {
616 UseSpans::ClosureUse { generator_kind, .. } => generator_kind,
617 _ => None,
618 }
619 }
620
b7449926 621 // Add a span label to the arguments of the closure, if it exists.
9fa01778
XL
622 pub(super) fn args_span_label(
623 self,
624 err: &mut DiagnosticBuilder<'_>,
625 message: impl Into<String>,
626 ) {
b7449926
XL
627 if let UseSpans::ClosureUse { args_span, .. } = self {
628 err.span_label(args_span, message);
629 }
630 }
631
632 // Add a span label to the use of the captured variable, if it exists.
9fa01778
XL
633 pub(super) fn var_span_label(
634 self,
635 err: &mut DiagnosticBuilder<'_>,
636 message: impl Into<String>,
637 ) {
b7449926
XL
638 if let UseSpans::ClosureUse { var_span, .. } = self {
639 err.span_label(var_span, message);
640 }
641 }
642
9fa01778 643 /// Returns `false` if this place is not used in a closure.
dc9dc135 644 pub(super) fn for_closure(&self) -> bool {
0bf4aa26 645 match *self {
e74abb32 646 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(),
0bf4aa26
XL
647 _ => false,
648 }
649 }
650
9fa01778 651 /// Returns `false` if this place is not used in a generator.
dc9dc135 652 pub(super) fn for_generator(&self) -> bool {
0bf4aa26 653 match *self {
e74abb32 654 UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(),
0bf4aa26
XL
655 _ => false,
656 }
657 }
658
659 /// Describe the span associated with a use of a place.
dc9dc135 660 pub(super) fn describe(&self) -> String {
0bf4aa26 661 match *self {
dfeec247
XL
662 UseSpans::ClosureUse { generator_kind, .. } => {
663 if generator_kind.is_some() {
664 " in generator".to_string()
665 } else {
666 " in closure".to_string()
667 }
668 }
1b1a35ee 669 _ => String::new(),
b7449926
XL
670 }
671 }
672
673 pub(super) fn or_else<F>(self, if_other: F) -> Self
674 where
675 F: FnOnce() -> Self,
676 {
677 match self {
678 closure @ UseSpans::ClosureUse { .. } => closure,
f035d41b
XL
679 UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
680 fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
b7449926
XL
681 }
682 }
683}
684
416331ca
XL
685pub(super) enum BorrowedContentSource<'tcx> {
686 DerefRawPointer,
687 DerefMutableRef,
688 DerefSharedRef,
689 OverloadedDeref(Ty<'tcx>),
690 OverloadedIndex(Ty<'tcx>),
691}
692
693impl BorrowedContentSource<'tcx> {
ba9703b0 694 pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
416331ca 695 match *self {
74b04a01
XL
696 BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
697 BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
698 BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
1b1a35ee 699 BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
ba9703b0 700 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
74b04a01 701 "an `Rc`".to_string()
ba9703b0
XL
702 }
703 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
74b04a01 704 "an `Arc`".to_string()
416331ca 705 }
ba9703b0
XL
706 _ => format!("dereference of `{}`", ty),
707 },
416331ca
XL
708 BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
709 }
710 }
711
712 pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
713 match *self {
714 BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
715 BorrowedContentSource::DerefSharedRef => Some("shared reference"),
716 BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
717 // Overloaded deref and index operators should be evaluated into a
718 // temporary. So we don't need a description here.
719 BorrowedContentSource::OverloadedDeref(_)
dfeec247 720 | BorrowedContentSource::OverloadedIndex(_) => None,
416331ca
XL
721 }
722 }
723
ba9703b0 724 pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
416331ca 725 match *self {
74b04a01
XL
726 BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
727 BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
416331ca 728 BorrowedContentSource::DerefMutableRef => {
dfeec247
XL
729 bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
730 }
1b1a35ee 731 BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
ba9703b0 732 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
74b04a01 733 "an `Rc`".to_string()
ba9703b0
XL
734 }
735 ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
74b04a01 736 "an `Arc`".to_string()
416331ca 737 }
ba9703b0
XL
738 _ => format!("a dereference of `{}`", ty),
739 },
416331ca
XL
740 BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
741 }
742 }
743
744 fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
1b1a35ee 745 match *func.kind() {
416331ca
XL
746 ty::FnDef(def_id, substs) => {
747 let trait_id = tcx.trait_of_item(def_id)?;
748
749 let lang_items = tcx.lang_items();
750 if Some(trait_id) == lang_items.deref_trait()
751 || Some(trait_id) == lang_items.deref_mut_trait()
752 {
753 Some(BorrowedContentSource::OverloadedDeref(substs.type_at(0)))
754 } else if Some(trait_id) == lang_items.index_trait()
755 || Some(trait_id) == lang_items.index_mut_trait()
756 {
757 Some(BorrowedContentSource::OverloadedIndex(substs.type_at(0)))
758 } else {
759 None
760 }
761 }
762 _ => None,
763 }
764 }
765}
766
dc9dc135 767impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
b7449926
XL
768 /// Finds the spans associated to a move or copy of move_place at location.
769 pub(super) fn move_spans(
770 &self,
74b04a01 771 moved_place: PlaceRef<'tcx>, // Could also be an upvar.
b7449926 772 location: Location,
1b1a35ee 773 ) -> UseSpans<'tcx> {
b7449926 774 use self::UseSpans::*;
b7449926 775
dc9dc135 776 let stmt = match self.body[location.block].statements.get(location.statement_index) {
b7449926 777 Some(stmt) => stmt,
dc9dc135 778 None => return OtherUse(self.body.source_info(location).span),
b7449926
XL
779 };
780
0bf4aa26 781 debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
dfeec247 782 if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) = stmt.kind {
f035d41b 783 match kind {
e74abb32 784 box AggregateKind::Closure(def_id, _)
f035d41b
XL
785 | box AggregateKind::Generator(def_id, _, _) => {
786 debug!("move_spans: def_id={:?} places={:?}", def_id, places);
787 if let Some((args_span, generator_kind, var_span)) =
788 self.closure_span(*def_id, moved_place, places)
789 {
790 return ClosureUse { generator_kind, args_span, var_span };
791 }
792 }
793 _ => {}
794 }
795 }
796
797 let normal_ret =
798 if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
799 PatUse(stmt.source_info.span)
800 } else {
801 OtherUse(stmt.source_info.span)
0bf4aa26
XL
802 };
803
f035d41b
XL
804 // We are trying to find MIR of the form:
805 // ```
806 // _temp = _moved_val;
807 // ...
808 // FnSelfCall(_temp, ...)
809 // ```
810 //
811 // where `_moved_val` is the place we generated the move error for,
812 // `_temp` is some other local, and `FnSelfCall` is a function
813 // that has a `self` parameter.
814
815 let target_temp = match stmt.kind {
816 StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
817 temp.as_local().unwrap()
b7449926 818 }
f035d41b
XL
819 _ => return normal_ret,
820 };
b7449926 821
f035d41b
XL
822 debug!("move_spans: target_temp = {:?}", target_temp);
823
824 if let Some(Terminator {
1b1a35ee 825 kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
f035d41b
XL
826 }) = &self.body[location.block].terminator
827 {
1b1a35ee
XL
828 let (method_did, method_substs) = if let Some(info) =
829 crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
830 {
831 info
832 } else {
833 return normal_ret;
834 };
f035d41b
XL
835
836 let tcx = self.infcx.tcx;
1b1a35ee
XL
837 let parent = tcx.parent(method_did);
838 let is_fn_once = parent == tcx.lang_items().fn_once_trait();
839 let is_operator = !from_hir_call
840 && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
841 let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
842 let fn_call_span = *fn_span;
843
844 let self_arg = tcx.fn_arg_names(method_did)[0];
845
846 debug!(
847 "terminator = {:?} from_hir_call={:?}",
848 self.body[location.block].terminator, from_hir_call
849 );
850
851 // Check for a 'special' use of 'self' -
852 // an FnOnce call, an operator (e.g. `<<`), or a
853 // deref coercion.
854 let kind = if is_fn_once {
855 Some(FnSelfUseKind::FnOnceCall)
856 } else if is_operator {
857 Some(FnSelfUseKind::Operator { self_arg })
858 } else if is_deref {
859 let deref_target =
860 tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
861 Instance::resolve(tcx, self.param_env, deref_target, method_substs)
862 .transpose()
863 });
864 if let Some(Ok(instance)) = deref_target {
865 let deref_target_ty = instance.ty(tcx, self.param_env);
866 Some(FnSelfUseKind::DerefCoercion {
867 deref_target: tcx.def_span(instance.def_id()),
868 deref_target_ty,
869 })
870 } else {
871 None
f035d41b 872 }
1b1a35ee
XL
873 } else {
874 None
875 };
876
877 let kind = kind.unwrap_or_else(|| {
878 // This isn't a 'special' use of `self`
879 debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
880 let implicit_into_iter = matches!(
881 fn_call_span.desugaring_kind(),
882 Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
883 );
884 FnSelfUseKind::Normal { self_arg, implicit_into_iter }
885 });
886
887 return FnSelfUse {
888 var_span: stmt.source_info.span,
889 fn_call_span,
890 fn_span: self
891 .infcx
892 .tcx
893 .sess
894 .source_map()
895 .guess_head_span(self.infcx.tcx.def_span(method_did)),
896 kind,
897 };
f035d41b 898 }
3dfed10e 899 normal_ret
b7449926
XL
900 }
901
902 /// Finds the span of arguments of a closure (within `maybe_closure_span`)
903 /// and its usage of the local assigned at `location`.
904 /// This is done by searching in statements succeeding `location`
905 /// and originating from `maybe_closure_span`.
1b1a35ee 906 pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
b7449926 907 use self::UseSpans::*;
0bf4aa26 908 debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
b7449926 909
dfeec247
XL
910 let target = match self.body[location.block].statements.get(location.statement_index) {
911 Some(&Statement { kind: StatementKind::Assign(box (ref place, _)), .. }) => {
e74abb32
XL
912 if let Some(local) = place.as_local() {
913 local
914 } else {
915 return OtherUse(use_span);
916 }
917 }
b7449926
XL
918 _ => return OtherUse(use_span),
919 };
920
dc9dc135 921 if self.body.local_kind(target) != LocalKind::Temp {
b7449926
XL
922 // operands are always temporaries.
923 return OtherUse(use_span);
924 }
925
dc9dc135 926 for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
dfeec247
XL
927 if let StatementKind::Assign(box (_, Rvalue::Aggregate(ref kind, ref places))) =
928 stmt.kind
929 {
0bf4aa26
XL
930 let (def_id, is_generator) = match kind {
931 box AggregateKind::Closure(def_id, _) => (def_id, false),
932 box AggregateKind::Generator(def_id, _, _) => (def_id, true),
933 _ => continue,
934 };
b7449926 935
0bf4aa26
XL
936 debug!(
937 "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
938 def_id, is_generator, places
939 );
dfeec247
XL
940 if let Some((args_span, generator_kind, var_span)) =
941 self.closure_span(*def_id, Place::from(target).as_ref(), places)
942 {
943 return ClosureUse { generator_kind, args_span, var_span };
0bf4aa26
XL
944 } else {
945 return OtherUse(use_span);
b7449926
XL
946 }
947 }
948
949 if use_span != stmt.source_info.span {
950 break;
951 }
952 }
953
954 OtherUse(use_span)
955 }
956
0bf4aa26
XL
957 /// Finds the span of a captured variable within a closure or generator.
958 fn closure_span(
959 &self,
960 def_id: DefId,
74b04a01 961 target_place: PlaceRef<'tcx>,
5869c6ff 962 places: &[Operand<'tcx>],
e74abb32 963 ) -> Option<(Span, Option<GeneratorKind>, Span)> {
0bf4aa26
XL
964 debug!(
965 "closure_span: def_id={:?} target_place={:?} places={:?}",
966 def_id, target_place, places
967 );
1b1a35ee
XL
968 let local_did = def_id.as_local()?;
969 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
e74abb32 970 let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
532ac7d7 971 debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
dfeec247 972 if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
6a06907d
XL
973 for (captured_place, place) in self
974 .infcx
975 .tcx
976 .typeck(def_id.expect_local())
977 .closure_min_captures_flattened(def_id)
978 .zip(places)
1b1a35ee 979 {
6a06907d
XL
980 let upvar_hir_id = captured_place.get_root_variable();
981 //FIXME(project-rfc-2229#8): Use better span from captured_place
982 let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;
48663c56 983 match place {
dfeec247
XL
984 Operand::Copy(place) | Operand::Move(place)
985 if target_place == place.as_ref() =>
986 {
48663c56 987 debug!("closure_span: found captured local {:?}", place);
e74abb32
XL
988 let body = self.infcx.tcx.hir().body(*body_id);
989 let generator_kind = body.generator_kind();
1b1a35ee
XL
990
991 // If we have a more specific span available, point to that.
992 // We do this even though this span might be part of a borrow error
993 // message rather than a move error message. Our goal is to point
994 // to a span that shows why the upvar is used in the closure,
995 // so a move-related span is as good as any (and potentially better,
996 // if the overall error is due to a move of the upvar).
6a06907d
XL
997
998 let usage_span = match captured_place.info.capture_kind {
999 ty::UpvarCapture::ByValue(Some(span)) => span,
1000 _ => span,
1001 };
1b1a35ee 1002 return Some((*args_span, generator_kind, usage_span));
dfeec247 1003 }
48663c56
XL
1004 _ => {}
1005 }
1006 }
0bf4aa26 1007 }
48663c56 1008 None
0bf4aa26
XL
1009 }
1010
b7449926
XL
1011 /// Helper to retrieve span(s) of given borrow from the current MIR
1012 /// representation
1b1a35ee 1013 pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
dc9dc135 1014 let span = self.body.source_info(borrow.reserve_location).span;
b7449926
XL
1015 self.borrow_spans(span, borrow.reserve_location)
1016 }
ff7c6d11 1017}