]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / conflict_errors.rs
CommitLineData
f9f354fc 1use either::Either;
5e7ed085 2use rustc_const_eval::util::CallKind;
923072b8 3use rustc_data_structures::captures::Captures;
dc9dc135 4use rustc_data_structures::fx::FxHashSet;
064997fb
FG
5use rustc_errors::{
6 struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
7};
dfeec247 8use rustc_hir as hir;
9ffffee4 9use rustc_hir::def::{DefKind, Res};
064997fb 10use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
487cf647 11use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
5e7ed085
FG
12use rustc_infer::infer::TyCtxtInferExt;
13use rustc_infer::traits::ObligationCause;
04454e1e 14use rustc_middle::mir::tcx::PlaceTy;
ba9703b0
XL
15use rustc_middle::mir::{
16 self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
17df50a5 17 FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
6a06907d 18 ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
ba9703b0 19};
2b03887a 20use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
c295e0f8 21use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
064997fb
FG
22use rustc_span::def_id::LocalDefId;
23use rustc_span::hygiene::DesugaringKind;
9c376795 24use rustc_span::symbol::{kw, sym};
064997fb 25use rustc_span::{BytePos, Span, Symbol};
136023e0 26use rustc_trait_selection::infer::InferCtxtExt;
dc9dc135 27
a2a8927a 28use crate::borrow_set::TwoPhaseActivation;
c295e0f8 29use crate::borrowck_errors;
dc9dc135 30
04454e1e 31use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
a2a8927a 32use crate::diagnostics::find_all_local_uses;
9c376795 33use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
c295e0f8 34use crate::{
6a06907d
XL
35 borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
36 InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
60c5eb7d
XL
37};
38
39use super::{
a2a8927a 40 explain_borrow::{BorrowExplanation, LaterUseKind},
064997fb 41 DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
60c5eb7d
XL
42};
43
dc9dc135
XL
44#[derive(Debug)]
45struct MoveSite {
46 /// Index of the "move out" that we found. The `MoveData` can
47 /// then tell us where the move occurred.
48 moi: MoveOutIndex,
49
50 /// `true` if we traversed a back edge while walking from the point
51 /// of error to the move site.
dfeec247 52 traversed_back_edge: bool,
dc9dc135
XL
53}
54
55/// Which case a StorageDeadOrDrop is for.
56#[derive(Copy, Clone, PartialEq, Eq, Debug)]
57enum StorageDeadOrDrop<'tcx> {
58 LocalStorageDead,
59 BoxedStorageDead,
60 Destructor(Ty<'tcx>),
61}
62
63impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
c295e0f8 64 pub(crate) fn report_use_of_moved_or_uninitialized(
dc9dc135
XL
65 &mut self,
66 location: Location,
67 desired_action: InitializationRequiringAction,
74b04a01 68 (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),
dc9dc135
XL
69 mpi: MovePathIndex,
70 ) {
71 debug!(
72 "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
73 moved_place={:?} used_place={:?} span={:?} mpi={:?}",
74 location, desired_action, moved_place, used_place, span, mpi
75 );
76
dfeec247
XL
77 let use_spans =
78 self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
dc9dc135
XL
79 let span = use_spans.args_or_use();
80
136023e0 81 let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);
1b1a35ee
XL
82 debug!(
83 "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
84 move_site_vec, use_spans
85 );
dfeec247
XL
86 let move_out_indices: Vec<_> =
87 move_site_vec.iter().map(|move_site| move_site.moi).collect();
dc9dc135
XL
88
89 if move_out_indices.is_empty() {
60c5eb7d 90 let root_place = PlaceRef { projection: &[], ..used_place };
dc9dc135 91
e74abb32 92 if !self.uninitialized_error_reported.insert(root_place) {
dc9dc135
XL
93 debug!(
94 "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
95 root_place
96 );
97 return;
98 }
99
064997fb
FG
100 let err = self.report_use_of_uninitialized(
101 mpi,
102 used_place,
103 moved_place,
104 desired_action,
dc9dc135 105 span,
064997fb 106 use_spans,
dc9dc135 107 );
5099ac24 108 self.buffer_error(err);
dc9dc135 109 } else {
5099ac24 110 if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
dfeec247 111 if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
dc9dc135 112 debug!(
064997fb 113 "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
dc9dc135
XL
114 move_out_indices
115 );
116 return;
117 }
118 }
119
1b1a35ee
XL
120 let is_partial_move = move_site_vec.iter().any(|move_site| {
121 let move_out = self.move_data.moves[(*move_site).moi];
122 let moved_place = &self.move_data.move_paths[move_out.path].place;
123 // `*(_1)` where `_1` is a `Box` is actually a move out.
29967ef6 124 let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref]
1b1a35ee
XL
125 && self.body.local_decls[moved_place.local].ty.is_box();
126
127 !is_box_move
128 && used_place != moved_place.as_ref()
129 && used_place.is_prefix_of(moved_place.as_ref())
130 });
131
132 let partial_str = if is_partial_move { "partial " } else { "" };
133 let partially_str = if is_partial_move { "partially " } else { "" };
dc9dc135 134
416331ca 135 let mut err = self.cannot_act_on_moved_value(
dc9dc135
XL
136 span,
137 desired_action.as_noun(),
1b1a35ee 138 partially_str,
064997fb
FG
139 self.describe_place_with_options(
140 moved_place,
141 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
142 ),
dc9dc135
XL
143 );
144
136023e0
XL
145 let reinit_spans = maybe_reinitialized_locations
146 .iter()
147 .take(3)
148 .map(|loc| {
149 self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)
150 .args_or_use()
151 })
152 .collect::<Vec<Span>>();
5e7ed085 153
136023e0
XL
154 let reinits = maybe_reinitialized_locations.len();
155 if reinits == 1 {
156 err.span_label(reinit_spans[0], "this reinitialization might get skipped");
157 } else if reinits > 1 {
158 err.span_note(
159 MultiSpan::from_spans(reinit_spans),
160 &if reinits <= 3 {
9c376795 161 format!("these {reinits} reinitializations might get skipped")
136023e0
XL
162 } else {
163 format!(
164 "these 3 reinitializations and {} other{} might get skipped",
165 reinits - 3,
166 if reinits == 4 { "" } else { "s" }
167 )
168 },
169 );
170 }
171
487cf647 172 let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
dc9dc135
XL
173
174 let mut is_loop_move = false;
5869c6ff 175 let mut in_pattern = false;
487cf647 176 let mut seen_spans = FxHashSet::default();
1b1a35ee 177
dc9dc135
XL
178 for move_site in &move_site_vec {
179 let move_out = self.move_data.moves[(*move_site).moi];
180 let moved_place = &self.move_data.move_paths[move_out.path].place;
181
416331ca 182 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
dc9dc135
XL
183 let move_span = move_spans.args_or_use();
184
dfeec247 185 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
dc9dc135 186
5869c6ff
XL
187 let loop_message = if location == move_out.source || move_site.traversed_back_edge {
188 ", in previous iteration of loop"
189 } else {
190 ""
191 };
192
f035d41b 193 if location == move_out.source {
dc9dc135 194 is_loop_move = true;
5869c6ff
XL
195 }
196
487cf647
FG
197 if !seen_spans.contains(&move_span) {
198 if !closure {
9c376795
FG
199 self.suggest_ref_or_clone(
200 mpi,
201 move_span,
202 &mut err,
203 &mut in_pattern,
204 move_spans,
205 );
136023e0 206 }
487cf647
FG
207
208 self.explain_captures(
209 &mut err,
210 span,
211 move_span,
212 move_spans,
213 *moved_place,
214 partially_str,
215 loop_message,
216 move_msg,
217 is_loop_move,
218 maybe_reinitialized_locations.is_empty(),
219 );
dc9dc135 220 }
487cf647 221 seen_spans.insert(move_span);
dc9dc135
XL
222 }
223
487cf647 224 use_spans.var_path_only_subdiag(&mut err, desired_action);
dc9dc135
XL
225
226 if !is_loop_move {
227 err.span_label(
228 span,
229 format!(
9c376795 230 "value {} here after {partial_str}move",
dc9dc135 231 desired_action.as_verb_in_past_tense(),
dc9dc135
XL
232 ),
233 );
234 }
235
5869c6ff 236 let ty = used_place.ty(self.body, self.infcx.tcx).ty;
1b1a35ee 237 let needs_note = match ty.kind() {
dc9dc135 238 ty::Closure(id, _) => {
9ffffee4 239 self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()
dc9dc135
XL
240 }
241 _ => true,
242 };
243
f035d41b
XL
244 let mpi = self.move_data.moves[move_out_indices[0]].path;
245 let place = &self.move_data.move_paths[mpi].place;
246 let ty = place.ty(self.body, self.infcx.tcx).ty;
247
5869c6ff 248 // If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
f2b60f7d
FG
249 // Same for if we're in a loop, see #101119.
250 if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
1b1a35ee 251 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
f035d41b
XL
252 // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
253 err.span_suggestion_verbose(
254 span.shrink_to_lo(),
255 &format!(
256 "consider creating a fresh reborrow of {} here",
257 self.describe_place(moved_place)
9c376795 258 .map(|n| format!("`{n}`"))
f035d41b
XL
259 .unwrap_or_else(|| "the mutable reference".to_string()),
260 ),
923072b8 261 "&mut *",
f035d41b
XL
262 Applicability::MachineApplicable,
263 );
264 }
265 }
dc9dc135 266
064997fb
FG
267 let opt_name = self.describe_place_with_options(
268 place.as_ref(),
269 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
270 );
5e7ed085 271 let note_msg = match opt_name {
9c376795 272 Some(name) => format!("`{name}`"),
5e7ed085
FG
273 None => "value".to_owned(),
274 };
275 if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
276 // Suppress the next suggestion since we don't want to put more bounds onto
277 // something that already has `Fn`-like bounds (or is a closure), so we can't
278 // restrict anyways.
279 } else {
280 self.suggest_adding_copy_bounds(&mut err, ty, span);
281 }
282
f035d41b 283 if needs_note {
e74abb32 284 let span = if let Some(local) = place.as_local() {
5e7ed085 285 Some(self.body.local_decls[local].source_info.span)
dc9dc135
XL
286 } else {
287 None
288 };
1b1a35ee
XL
289 self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
290 }
291
292 if let UseSpans::FnSelfUse {
5099ac24 293 kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
1b1a35ee
XL
294 ..
295 } = use_spans
296 {
297 err.note(&format!(
9c376795 298 "{} occurs due to deref coercion to `{deref_target_ty}`",
1b1a35ee 299 desired_action.as_noun(),
1b1a35ee
XL
300 ));
301
c295e0f8 302 // Check first whether the source is accessible (issue #87060)
064997fb 303 if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) {
c295e0f8
XL
304 err.span_note(deref_target, "deref defined here");
305 }
dc9dc135
XL
306 }
307
5099ac24 308 self.buffer_move_error(move_out_indices, (used_place, err));
dc9dc135
XL
309 }
310 }
311
487cf647
FG
312 fn suggest_ref_or_clone(
313 &mut self,
314 mpi: MovePathIndex,
315 move_span: Span,
316 err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
317 in_pattern: &mut bool,
9c376795 318 move_spans: UseSpans<'_>,
487cf647
FG
319 ) {
320 struct ExpressionFinder<'hir> {
321 expr_span: Span,
322 expr: Option<&'hir hir::Expr<'hir>>,
323 pat: Option<&'hir hir::Pat<'hir>>,
324 parent_pat: Option<&'hir hir::Pat<'hir>>,
325 }
326 impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
327 fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
328 if e.span == self.expr_span {
329 self.expr = Some(e);
330 }
331 hir::intravisit::walk_expr(self, e);
332 }
333 fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
334 if p.span == self.expr_span {
335 self.pat = Some(p);
336 }
337 if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind {
338 if i.span == self.expr_span || p.span == self.expr_span {
339 self.pat = Some(p);
340 }
341 // Check if we are in a situation of `ident @ ident` where we want to suggest
342 // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
343 if let Some(subpat) = sub && self.pat.is_none() {
344 self.visit_pat(subpat);
345 if self.pat.is_some() {
346 self.parent_pat = Some(p);
347 }
348 return;
349 }
350 }
351 hir::intravisit::walk_pat(self, p);
352 }
353 }
354 let hir = self.infcx.tcx.hir();
355 if let Some(hir::Node::Item(hir::Item {
356 kind: hir::ItemKind::Fn(_, _, body_id),
357 ..
9c376795 358 })) = hir.find(self.mir_hir_id())
487cf647
FG
359 && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
360 {
361 let place = &self.move_data.move_paths[mpi].place;
362 let span = place.as_local()
363 .map(|local| self.body.local_decls[local].source_info.span);
364 let mut finder = ExpressionFinder {
365 expr_span: move_span,
366 expr: None,
367 pat: None,
368 parent_pat: None,
369 };
370 finder.visit_expr(expr);
371 if let Some(span) = span && let Some(expr) = finder.expr {
372 for (_, expr) in hir.parent_iter(expr.hir_id) {
373 if let hir::Node::Expr(expr) = expr {
374 if expr.span.contains(span) {
375 // If the let binding occurs within the same loop, then that
376 // loop isn't relevant, like in the following, the outermost `loop`
377 // doesn't play into `x` being moved.
378 // ```
379 // loop {
380 // let x = String::new();
381 // loop {
382 // foo(x);
383 // }
384 // }
385 // ```
386 break;
387 }
388 if let hir::ExprKind::Loop(.., loop_span) = expr.kind {
389 err.span_label(loop_span, "inside of this loop");
390 }
391 }
392 }
393 let typeck = self.infcx.tcx.typeck(self.mir_def_id());
9c376795 394 let hir_id = hir.parent_id(expr.hir_id);
487cf647
FG
395 if let Some(parent) = hir.find(hir_id) {
396 let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
397 && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
398 && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
399 {
400 (def_id.as_local(), args, 1)
401 } else if let hir::Node::Expr(parent_expr) = parent
402 && let hir::ExprKind::Call(call, args) = parent_expr.kind
403 && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
404 {
405 (def_id.as_local(), args, 0)
406 } else {
407 (None, &[][..], 0)
408 };
409 if let Some(def_id) = def_id
410 && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
411 && let Some(fn_sig) = node.fn_sig()
412 && let Some(ident) = node.ident()
413 && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
414 && let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
415 {
416 let mut span: MultiSpan = arg.span.into();
417 span.push_span_label(
418 arg.span,
419 "this parameter takes ownership of the value".to_string(),
420 );
421 let descr = match node.fn_kind() {
422 Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
423 Some(hir::intravisit::FnKind::Method(..)) => "method",
424 Some(hir::intravisit::FnKind::Closure) => "closure",
425 };
426 span.push_span_label(
427 ident.span,
428 format!("in this {descr}"),
429 );
430 err.span_note(
431 span,
432 format!(
433 "consider changing this parameter type in {descr} `{ident}` to \
434 borrow instead if owning the value isn't necessary",
435 ),
436 );
437 }
438 let place = &self.move_data.move_paths[mpi].place;
439 let ty = place.ty(self.body, self.infcx.tcx).ty;
440 if let hir::Node::Expr(parent_expr) = parent
441 && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
442 && let hir::ExprKind::Path(
443 hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _)
444 ) = call_expr.kind
445 {
446 // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
9c376795
FG
447 } else if let UseSpans::FnSelfUse {
448 kind: CallKind::Normal { .. },
449 ..
450 } = move_spans {
451 // We already suggest cloning for these cases in `explain_captures`.
487cf647
FG
452 } else {
453 self.suggest_cloning(err, ty, move_span);
454 }
455 }
456 }
457 if let Some(pat) = finder.pat {
458 *in_pattern = true;
459 let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
460 if let Some(pat) = finder.parent_pat {
461 sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));
462 }
463 err.multipart_suggestion_verbose(
464 "borrow this binding in the pattern to avoid moving the value",
465 sugg,
466 Applicability::MachineApplicable,
467 );
468 }
469 }
470 }
471
064997fb
FG
472 fn report_use_of_uninitialized(
473 &self,
474 mpi: MovePathIndex,
475 used_place: PlaceRef<'tcx>,
476 moved_place: PlaceRef<'tcx>,
477 desired_action: InitializationRequiringAction,
478 span: Span,
479 use_spans: UseSpans<'tcx>,
480 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
481 // We need all statements in the body where the binding was assigned to to later find all
482 // the branching code paths where the binding *wasn't* assigned to.
483 let inits = &self.move_data.init_path_map[mpi];
484 let move_path = &self.move_data.move_paths[mpi];
485 let decl_span = self.body.local_decls[move_path.place.local].source_info.span;
486 let mut spans = vec![];
487 for init_idx in inits {
488 let init = &self.move_data.inits[*init_idx];
489 let span = init.span(&self.body);
490 if !span.is_dummy() {
491 spans.push(span);
492 }
493 }
494
495 let (name, desc) = match self.describe_place_with_options(
496 moved_place,
497 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
498 ) {
499 Some(name) => (format!("`{name}`"), format!("`{name}` ")),
500 None => ("the variable".to_string(), String::new()),
501 };
502 let path = match self.describe_place_with_options(
503 used_place,
504 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
505 ) {
506 Some(name) => format!("`{name}`"),
507 None => "value".to_string(),
508 };
509
510 // We use the statements were the binding was initialized, and inspect the HIR to look
511 // for the branching codepaths that aren't covered, to point at them.
512 let map = self.infcx.tcx.hir();
513 let body_id = map.body_owned_by(self.mir_def_id());
514 let body = map.body(body_id);
515
516 let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
517 visitor.visit_body(&body);
518
2b03887a 519 let mut show_assign_sugg = false;
064997fb
FG
520 let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
521 | InitializationRequiringAction::Assignment = desired_action
522 {
523 // The same error is emitted for bindings that are *sometimes* initialized and the ones
524 // that are *partially* initialized by assigning to a field of an uninitialized
525 // binding. We differentiate between them for more accurate wording here.
526 "isn't fully initialized"
9c376795
FG
527 } else if !spans.iter().any(|i| {
528 // We filter these to avoid misleading wording in cases like the following,
529 // where `x` has an `init`, but it is in the same place we're looking at:
530 // ```
531 // let x;
532 // x += 1;
533 // ```
534 !i.contains(span)
535 // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
536 && !visitor
537 .errors
538 .iter()
539 .map(|(sp, _)| *sp)
540 .any(|sp| span < sp && !sp.contains(span))
541 }) {
2b03887a 542 show_assign_sugg = true;
064997fb
FG
543 "isn't initialized"
544 } else {
545 "is possibly-uninitialized"
546 };
547
548 let used = desired_action.as_general_verb_in_past_tense();
549 let mut err =
550 struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}");
487cf647 551 use_spans.var_path_only_subdiag(&mut err, desired_action);
064997fb
FG
552
553 if let InitializationRequiringAction::PartialAssignment
554 | InitializationRequiringAction::Assignment = desired_action
555 {
556 err.help(
557 "partial initialization isn't supported, fully initialize the binding with a \
558 default value and mutate it, or use `std::mem::MaybeUninit`",
559 );
560 }
561 err.span_label(span, format!("{path} {used} here but it {isnt_initialized}"));
562
563 let mut shown = false;
564 for (sp, label) in visitor.errors {
565 if sp < span && !sp.overlaps(span) {
566 // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention
567 // match arms coming after the primary span because they aren't relevant:
568 // ```
569 // let x;
570 // match y {
571 // _ if { x = 2; true } => {}
572 // _ if {
573 // x; //~ ERROR
574 // false
575 // } => {}
576 // _ => {} // We don't want to point to this.
577 // };
578 // ```
579 err.span_label(sp, &label);
580 shown = true;
581 }
582 }
583 if !shown {
584 for sp in &spans {
585 if *sp < span && !sp.overlaps(span) {
586 err.span_label(*sp, "binding initialized here in some conditions");
587 }
588 }
589 }
2b03887a 590
064997fb 591 err.span_label(decl_span, "binding declared here but left uninitialized");
2b03887a
FG
592 if show_assign_sugg {
593 struct LetVisitor {
594 decl_span: Span,
595 sugg_span: Option<Span>,
596 }
597
598 impl<'v> Visitor<'v> for LetVisitor {
599 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
600 if self.sugg_span.is_some() {
601 return;
602 }
603 if let hir::StmtKind::Local(hir::Local {
604 span, ty, init: None, ..
605 }) = &ex.kind && span.contains(self.decl_span) {
606 self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
607 }
608 hir::intravisit::walk_stmt(self, ex);
609 }
610 }
611
612 let mut visitor = LetVisitor { decl_span, sugg_span: None };
613 visitor.visit_body(&body);
614 if let Some(span) = visitor.sugg_span {
615 self.suggest_assign_value(&mut err, moved_place, span);
616 }
617 }
064997fb
FG
618 err
619 }
620
2b03887a
FG
621 fn suggest_assign_value(
622 &self,
623 err: &mut Diagnostic,
624 moved_place: PlaceRef<'tcx>,
625 sugg_span: Span,
626 ) {
627 let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
628 debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
629
630 let tcx = self.infcx.tcx;
631 let implements_default = |ty, param_env| {
632 let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
633 return false;
634 };
635 // Regions are already solved, so we must use a fresh InferCtxt,
636 // but the type has region variables, so erase those.
637 tcx.infer_ctxt()
638 .build()
487cf647 639 .type_implements_trait(default_trait, [tcx.erase_regions(ty)], param_env)
2b03887a
FG
640 .must_apply_modulo_regions()
641 };
642
643 let assign_value = match ty.kind() {
644 ty::Bool => "false",
645 ty::Float(_) => "0.0",
646 ty::Int(_) | ty::Uint(_) => "0",
647 ty::Never | ty::Error(_) => "",
648 ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
649 ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
650 _ => "todo!()",
651 };
652
653 if !assign_value.is_empty() {
654 err.span_suggestion_verbose(
655 sugg_span.shrink_to_hi(),
9c376795 656 "consider assigning a value",
2b03887a
FG
657 format!(" = {}", assign_value),
658 Applicability::MaybeIncorrect,
659 );
660 }
661 }
662
5e7ed085
FG
663 fn suggest_borrow_fn_like(
664 &self,
f2b60f7d 665 err: &mut Diagnostic,
5e7ed085
FG
666 ty: Ty<'tcx>,
667 move_sites: &[MoveSite],
668 value_name: &str,
669 ) -> bool {
670 let tcx = self.infcx.tcx;
671
672 // Find out if the predicates show that the type is a Fn or FnMut
9c376795
FG
673 let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
674 if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
675 && pred.self_ty() == ty
676 {
677 if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
678 return Some(hir::Mutability::Not);
679 } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
680 return Some(hir::Mutability::Mut);
5e7ed085 681 }
9c376795
FG
682 }
683 None
487cf647 684 };
5e7ed085
FG
685
686 // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
687 // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
688 // These types seem reasonably opaque enough that they could be substituted with their
689 // borrowed variants in a function body when we see a move error.
9c376795
FG
690 let borrow_level = match *ty.kind() {
691 ty::Param(_) => tcx
692 .explicit_predicates_of(self.mir_def_id().to_def_id())
693 .predicates
694 .iter()
695 .copied()
696 .find_map(find_fn_kind_from_did),
697 ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
698 .bound_explicit_item_bounds(def_id)
699 .subst_iter_copied(tcx, substs)
700 .find_map(find_fn_kind_from_did),
5e7ed085
FG
701 ty::Closure(_, substs) => match substs.as_closure().kind() {
702 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
703 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
704 _ => None,
705 },
706 _ => None,
707 };
708
709 let Some(borrow_level) = borrow_level else { return false; };
710 let sugg = move_sites
711 .iter()
712 .map(|move_site| {
713 let move_out = self.move_data.moves[(*move_site).moi];
714 let moved_place = &self.move_data.move_paths[move_out.path].place;
715 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
716 let move_span = move_spans.args_or_use();
487cf647 717 let suggestion = borrow_level.ref_prefix_str().to_owned();
5e7ed085
FG
718 (move_span.shrink_to_lo(), suggestion)
719 })
720 .collect();
721 err.multipart_suggestion_verbose(
487cf647 722 format!("consider {}borrowing {value_name}", borrow_level.mutably_str()),
5e7ed085
FG
723 sugg,
724 Applicability::MaybeIncorrect,
725 );
726 true
727 }
728
487cf647
FG
729 fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
730 let tcx = self.infcx.tcx;
731 // Try to find predicates on *generic params* that would allow copying `ty`
732 let infcx = tcx.infer_ctxt().build();
733
734 if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
735 && infcx
736 .type_implements_trait(
737 clone_trait_def,
738 [tcx.erase_regions(ty)],
739 self.param_env,
740 )
741 .must_apply_modulo_regions()
742 {
743 err.span_suggestion_verbose(
744 span.shrink_to_hi(),
745 "consider cloning the value if the performance cost is acceptable",
9c376795 746 ".clone()",
487cf647
FG
747 Applicability::MachineApplicable,
748 );
749 }
750 }
751
f2b60f7d 752 fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
5e7ed085
FG
753 let tcx = self.infcx.tcx;
754 let generics = tcx.generics_of(self.mir_def_id());
755
756 let Some(hir_generics) = tcx
757 .typeck_root_def_id(self.mir_def_id().to_def_id())
758 .as_local()
759 .and_then(|def_id| tcx.hir().get_generics(def_id))
760 else { return; };
761 // Try to find predicates on *generic params* that would allow copying `ty`
2b03887a 762 let infcx = tcx.infer_ctxt().build();
487cf647 763 let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
2b03887a
FG
764 let cause = ObligationCause::new(
765 span,
9ffffee4 766 self.mir_def_id(),
2b03887a
FG
767 rustc_infer::traits::ObligationCauseCode::MiscObligation,
768 );
487cf647 769 let errors = rustc_trait_selection::traits::fully_solve_bound(
2b03887a 770 &infcx,
487cf647 771 cause,
2b03887a
FG
772 self.param_env,
773 // Erase any region vids from the type, which may not be resolved
774 infcx.tcx.erase_regions(ty),
775 copy_did,
2b03887a 776 );
2b03887a
FG
777
778 // Only emit suggestion if all required predicates are on generic
779 let predicates: Result<Vec<_>, _> = errors
780 .into_iter()
781 .map(|err| match err.obligation.predicate.kind().skip_binder() {
487cf647
FG
782 PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
783 match predicate.self_ty().kind() {
784 ty::Param(param_ty) => Ok((
785 generics.type_param(param_ty, tcx),
786 predicate.trait_ref.print_only_trait_path().to_string(),
787 )),
788 _ => Err(()),
789 }
790 }
2b03887a
FG
791 _ => Err(()),
792 })
793 .collect();
5e7ed085
FG
794
795 if let Ok(predicates) = predicates {
796 suggest_constraining_type_params(
797 tcx,
798 hir_generics,
799 err,
800 predicates
801 .iter()
802 .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
9ffffee4 803 None,
5e7ed085
FG
804 );
805 }
806 }
807
c295e0f8 808 pub(crate) fn report_move_out_while_borrowed(
dc9dc135
XL
809 &mut self,
810 location: Location,
ba9703b0 811 (place, span): (Place<'tcx>, Span),
dc9dc135
XL
812 borrow: &BorrowData<'tcx>,
813 ) {
814 debug!(
815 "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
816 location, place, span, borrow
817 );
ba9703b0
XL
818 let value_msg = self.describe_any_place(place.as_ref());
819 let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
dc9dc135
XL
820
821 let borrow_spans = self.retrieve_borrow_spans(borrow);
822 let borrow_span = borrow_spans.args_or_use();
823
416331ca 824 let move_spans = self.move_spans(place.as_ref(), location);
dc9dc135
XL
825 let span = move_spans.args_or_use();
826
487cf647
FG
827 let mut err = self.cannot_move_when_borrowed(
828 span,
829 borrow_span,
830 &self.describe_any_place(place.as_ref()),
831 &borrow_msg,
832 &value_msg,
dc9dc135
XL
833 );
834
487cf647
FG
835 borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
836
17df50a5
XL
837 move_spans.var_span_label(
838 &mut err,
839 format!("move occurs due to use{}", move_spans.describe()),
840 "moved",
841 );
dc9dc135 842
dfeec247
XL
843 self.explain_why_borrow_contains_point(location, borrow, None)
844 .add_explanation_to_diagnostic(
845 self.infcx.tcx,
846 &self.body,
847 &self.local_names,
848 &mut err,
849 "",
850 Some(borrow_span),
136023e0 851 None,
dfeec247 852 );
5099ac24 853 self.buffer_error(err);
dc9dc135
XL
854 }
855
c295e0f8 856 pub(crate) fn report_use_while_mutably_borrowed(
dc9dc135
XL
857 &mut self,
858 location: Location,
ba9703b0 859 (place, _span): (Place<'tcx>, Span),
dc9dc135 860 borrow: &BorrowData<'tcx>,
5e7ed085 861 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dc9dc135
XL
862 let borrow_spans = self.retrieve_borrow_spans(borrow);
863 let borrow_span = borrow_spans.args_or_use();
864
865 // Conflicting borrows are reported separately, so only check for move
866 // captures.
416331ca 867 let use_spans = self.move_spans(place.as_ref(), location);
dc9dc135
XL
868 let span = use_spans.var_or_use();
869
17df50a5
XL
870 // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use
871 // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
416331ca 872 let mut err = self.cannot_use_when_mutably_borrowed(
dc9dc135 873 span,
ba9703b0 874 &self.describe_any_place(place.as_ref()),
dc9dc135 875 borrow_span,
ba9703b0 876 &self.describe_any_place(borrow.borrowed_place.as_ref()),
dc9dc135 877 );
487cf647
FG
878 borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
879 use crate::session_diagnostics::CaptureVarCause::*;
880 let place = &borrow.borrowed_place;
881 let desc_place = self.describe_any_place(place.as_ref());
882 match kind {
883 Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span },
884 None => BorrowUsePlaceClosure { place: desc_place, var_span },
885 }
886 });
dc9dc135
XL
887
888 self.explain_why_borrow_contains_point(location, borrow, None)
60c5eb7d
XL
889 .add_explanation_to_diagnostic(
890 self.infcx.tcx,
891 &self.body,
892 &self.local_names,
893 &mut err,
894 "",
895 None,
136023e0 896 None,
60c5eb7d 897 );
dc9dc135
XL
898 err
899 }
900
c295e0f8 901 pub(crate) fn report_conflicting_borrow(
dc9dc135
XL
902 &mut self,
903 location: Location,
ba9703b0 904 (place, span): (Place<'tcx>, Span),
dc9dc135
XL
905 gen_borrow_kind: BorrowKind,
906 issued_borrow: &BorrowData<'tcx>,
5e7ed085 907 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dc9dc135
XL
908 let issued_spans = self.retrieve_borrow_spans(issued_borrow);
909 let issued_span = issued_spans.args_or_use();
910
911 let borrow_spans = self.borrow_spans(span, location);
912 let span = borrow_spans.args_or_use();
913
914 let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
915 "generator"
916 } else {
917 "closure"
918 };
919
920 let (desc_place, msg_place, msg_borrow, union_type_name) =
ba9703b0 921 self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);
dc9dc135
XL
922
923 let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
dfeec247 924 let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };
dc9dc135
XL
925
926 // FIXME: supply non-"" `opt_via` when appropriate
dc9dc135 927 let first_borrow_desc;
dfeec247 928 let mut err = match (gen_borrow_kind, issued_borrow.kind) {
60c5eb7d 929 (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
dc9dc135 930 first_borrow_desc = "mutable ";
416331ca 931 self.cannot_reborrow_already_borrowed(
dc9dc135
XL
932 span,
933 &desc_place,
934 &msg_place,
60c5eb7d 935 "immutable",
dc9dc135
XL
936 issued_span,
937 "it",
60c5eb7d 938 "mutable",
dc9dc135
XL
939 &msg_borrow,
940 None,
dc9dc135
XL
941 )
942 }
60c5eb7d 943 (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
dc9dc135 944 first_borrow_desc = "immutable ";
9c376795 945 let mut err = self.cannot_reborrow_already_borrowed(
dc9dc135
XL
946 span,
947 &desc_place,
948 &msg_place,
60c5eb7d 949 "mutable",
dc9dc135
XL
950 issued_span,
951 "it",
60c5eb7d 952 "immutable",
dc9dc135
XL
953 &msg_borrow,
954 None,
9c376795
FG
955 );
956 self.suggest_binding_for_closure_capture_self(
957 &mut err,
958 issued_borrow.borrowed_place,
959 &issued_spans,
960 );
961 err
dc9dc135
XL
962 }
963
60c5eb7d 964 (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
dc9dc135 965 first_borrow_desc = "first ";
74b04a01 966 let mut err = self.cannot_mutably_borrow_multiply(
dc9dc135
XL
967 span,
968 &desc_place,
969 &msg_place,
970 issued_span,
971 &msg_borrow,
972 None,
74b04a01
XL
973 );
974 self.suggest_split_at_mut_if_applicable(
975 &mut err,
ba9703b0
XL
976 place,
977 issued_borrow.borrowed_place,
74b04a01
XL
978 );
979 err
dc9dc135
XL
980 }
981
60c5eb7d 982 (BorrowKind::Unique, BorrowKind::Unique) => {
dc9dc135 983 first_borrow_desc = "first ";
dfeec247 984 self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
dc9dc135
XL
985 }
986
ba9703b0 987 (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
dfeec247 988 if let Some(immutable_section_description) =
ba9703b0 989 self.classify_immutable_section(issued_borrow.assigned_place)
dfeec247 990 {
60c5eb7d
XL
991 let mut err = self.cannot_mutate_in_immutable_section(
992 span,
993 issued_span,
994 &desc_place,
995 immutable_section_description,
996 "mutably borrow",
997 );
998 borrow_spans.var_span_label(
999 &mut err,
1000 format!(
ba9703b0 1001 "borrow occurs due to use of {}{}",
60c5eb7d
XL
1002 desc_place,
1003 borrow_spans.describe(),
1004 ),
17df50a5 1005 "immutable",
60c5eb7d 1006 );
dc9dc135 1007
60c5eb7d
XL
1008 return err;
1009 } else {
1010 first_borrow_desc = "immutable ";
1011 self.cannot_reborrow_already_borrowed(
1012 span,
1013 &desc_place,
1014 &msg_place,
1015 "mutable",
1016 issued_span,
1017 "it",
1018 "immutable",
1019 &msg_borrow,
1020 None,
1021 )
1022 }
dc9dc135
XL
1023 }
1024
60c5eb7d 1025 (BorrowKind::Unique, _) => {
dc9dc135 1026 first_borrow_desc = "first ";
416331ca 1027 self.cannot_uniquely_borrow_by_one_closure(
dc9dc135
XL
1028 span,
1029 container_name,
1030 &desc_place,
1031 "",
1032 issued_span,
1033 "it",
1034 "",
1035 None,
dc9dc135 1036 )
dfeec247 1037 }
dc9dc135 1038
60c5eb7d 1039 (BorrowKind::Shared, BorrowKind::Unique) => {
dc9dc135 1040 first_borrow_desc = "first ";
416331ca 1041 self.cannot_reborrow_already_uniquely_borrowed(
dc9dc135
XL
1042 span,
1043 container_name,
1044 &desc_place,
1045 "",
60c5eb7d 1046 "immutable",
dc9dc135
XL
1047 issued_span,
1048 "",
1049 None,
1050 second_borrow_desc,
dc9dc135
XL
1051 )
1052 }
1053
60c5eb7d 1054 (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
dc9dc135 1055 first_borrow_desc = "first ";
416331ca 1056 self.cannot_reborrow_already_uniquely_borrowed(
dc9dc135
XL
1057 span,
1058 container_name,
1059 &desc_place,
1060 "",
60c5eb7d 1061 "mutable",
dc9dc135
XL
1062 issued_span,
1063 "",
1064 None,
1065 second_borrow_desc,
dc9dc135
XL
1066 )
1067 }
1068
ba9703b0
XL
1069 (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
1070 | (
1071 BorrowKind::Shallow,
1072 BorrowKind::Mut { .. }
1073 | BorrowKind::Unique
1074 | BorrowKind::Shared
1075 | BorrowKind::Shallow,
1076 ) => unreachable!(),
dc9dc135
XL
1077 };
1078
1079 if issued_spans == borrow_spans {
1080 borrow_spans.var_span_label(
1081 &mut err,
17df50a5
XL
1082 format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
1083 gen_borrow_kind.describe_mutability(),
dc9dc135
XL
1084 );
1085 } else {
1086 let borrow_place = &issued_borrow.borrowed_place;
ba9703b0 1087 let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
dc9dc135
XL
1088 issued_spans.var_span_label(
1089 &mut err,
1090 format!(
ba9703b0 1091 "first borrow occurs due to use of {}{}",
dc9dc135
XL
1092 borrow_place_desc,
1093 issued_spans.describe(),
1094 ),
17df50a5 1095 issued_borrow.kind.describe_mutability(),
dc9dc135
XL
1096 );
1097
1098 borrow_spans.var_span_label(
1099 &mut err,
1100 format!(
ba9703b0 1101 "second borrow occurs due to use of {}{}",
dc9dc135
XL
1102 desc_place,
1103 borrow_spans.describe(),
1104 ),
17df50a5 1105 gen_borrow_kind.describe_mutability(),
dc9dc135
XL
1106 );
1107 }
1108
1109 if union_type_name != "" {
1110 err.note(&format!(
ba9703b0 1111 "{} is a field of the union `{}`, so it overlaps the field {}",
dc9dc135
XL
1112 msg_place, union_type_name, msg_borrow,
1113 ));
1114 }
1115
1116 explanation.add_explanation_to_diagnostic(
1117 self.infcx.tcx,
60c5eb7d
XL
1118 &self.body,
1119 &self.local_names,
dc9dc135
XL
1120 &mut err,
1121 first_borrow_desc,
1122 None,
136023e0 1123 Some((issued_span, span)),
dc9dc135
XL
1124 );
1125
04454e1e 1126 self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
a2a8927a 1127
dc9dc135
XL
1128 err
1129 }
1130
a2a8927a
XL
1131 #[instrument(level = "debug", skip(self, err))]
1132 fn suggest_using_local_if_applicable(
1133 &self,
5e7ed085 1134 err: &mut Diagnostic,
a2a8927a 1135 location: Location,
a2a8927a 1136 issued_borrow: &BorrowData<'tcx>,
923072b8 1137 explanation: BorrowExplanation<'tcx>,
a2a8927a 1138 ) {
04454e1e
FG
1139 let used_in_call = matches!(
1140 explanation,
1141 BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _)
1142 );
a2a8927a
XL
1143 if !used_in_call {
1144 debug!("not later used in call");
1145 return;
1146 }
1147
04454e1e
FG
1148 let use_span =
1149 if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation {
1150 Some(use_span)
1151 } else {
1152 None
1153 };
1154
a2a8927a
XL
1155 let outer_call_loc =
1156 if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
1157 loc
1158 } else {
1159 issued_borrow.reserve_location
1160 };
1161 let outer_call_stmt = self.body.stmt_at(outer_call_loc);
1162
1163 let inner_param_location = location;
1164 let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
1165 debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
1166 return;
1167 };
1168 let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
1169 debug!(
1170 "`inner_param_location` {:?} is not for an assignment: {:?}",
1171 inner_param_location, inner_param_stmt
1172 );
1173 return;
1174 };
1175 let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
04454e1e 1176 let Some((inner_call_loc, inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
a2a8927a
XL
1177 let Either::Right(term) = self.body.stmt_at(loc) else {
1178 debug!("{:?} is a statement, so it can't be a call", loc);
1179 return None;
1180 };
1181 let TerminatorKind::Call { args, .. } = &term.kind else {
1182 debug!("not a call: {:?}", term);
1183 return None;
1184 };
1185 debug!("checking call args for uses of inner_param: {:?}", args);
9ffffee4 1186 args.contains(&Operand::Move(inner_param)).then_some((loc, term))
a2a8927a
XL
1187 }) else {
1188 debug!("no uses of inner_param found as a by-move call arg");
1189 return;
1190 };
1191 debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
1192
1193 let inner_call_span = inner_call_term.source_info.span;
04454e1e
FG
1194 let outer_call_span = match use_span {
1195 Some(span) => span,
1196 None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span,
1197 };
a2a8927a
XL
1198 if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
1199 // FIXME: This stops the suggestion in some cases where it should be emitted.
1200 // Fix the spans for those cases so it's emitted correctly.
1201 debug!(
1202 "outer span {:?} does not strictly contain inner span {:?}",
1203 outer_call_span, inner_call_span
1204 );
1205 return;
1206 }
04454e1e
FG
1207 err.span_help(
1208 inner_call_span,
1209 &format!(
1210 "try adding a local storing this{}...",
1211 if use_span.is_some() { "" } else { " argument" }
1212 ),
1213 );
1214 err.span_help(
1215 outer_call_span,
1216 &format!(
1217 "...and then using that local {}",
1218 if use_span.is_some() { "here" } else { "as the argument to this call" }
1219 ),
1220 );
a2a8927a
XL
1221 }
1222
74b04a01
XL
1223 fn suggest_split_at_mut_if_applicable(
1224 &self,
5e7ed085 1225 err: &mut Diagnostic,
ba9703b0
XL
1226 place: Place<'tcx>,
1227 borrowed_place: Place<'tcx>,
74b04a01 1228 ) {
ba9703b0
XL
1229 if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
1230 (&place.projection[..], &borrowed_place.projection[..])
1231 {
1232 err.help(
1233 "consider using `.split_at_mut(position)` or similar method to obtain \
74b04a01 1234 two mutable non-overlapping sub-slices",
ba9703b0 1235 );
74b04a01
XL
1236 }
1237 }
1238
9c376795
FG
1239 fn suggest_binding_for_closure_capture_self(
1240 &self,
1241 err: &mut Diagnostic,
1242 borrowed_place: Place<'tcx>,
1243 issued_spans: &UseSpans<'tcx>,
1244 ) {
1245 let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
1246 let hir = self.infcx.tcx.hir();
1247
1248 // check whether the borrowed place is capturing `self` by mut reference
1249 let local = borrowed_place.local;
1250 let Some(_) = self
1251 .body
1252 .local_decls
1253 .get(local)
1254 .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
1255
1256 struct ExpressionFinder<'hir> {
1257 capture_span: Span,
1258 closure_change_spans: Vec<Span>,
1259 closure_arg_span: Option<Span>,
1260 in_closure: bool,
1261 suggest_arg: String,
1262 hir: rustc_middle::hir::map::Map<'hir>,
1263 closure_local_id: Option<hir::HirId>,
1264 closure_call_changes: Vec<(Span, String)>,
1265 }
1266 impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
1267 fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
1268 if e.span.contains(self.capture_span) {
1269 if let hir::ExprKind::Closure(&hir::Closure {
1270 movability: None,
1271 body,
1272 fn_arg_span,
1273 fn_decl: hir::FnDecl{ inputs, .. },
1274 ..
1275 }) = e.kind &&
1276 let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
1277 self.suggest_arg = "this: &Self".to_string();
1278 if inputs.len() > 0 {
1279 self.suggest_arg.push_str(", ");
1280 }
1281 self.in_closure = true;
1282 self.closure_arg_span = fn_arg_span;
1283 self.visit_expr(body);
1284 self.in_closure = false;
1285 }
1286 }
1287 if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
1288 if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
1289 seg.ident.name == kw::SelfLower && self.in_closure {
1290 self.closure_change_spans.push(e.span);
1291 }
1292 }
1293 hir::intravisit::walk_expr(self, e);
1294 }
1295
1296 fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
1297 if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
1298 let Some(init) = local.init
1299 {
1300 if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
1301 movability: None,
1302 ..
1303 }), .. } = init &&
1304 init.span.contains(self.capture_span) {
1305 self.closure_local_id = Some(*hir_id);
1306 }
1307 }
1308 hir::intravisit::walk_local(self, local);
1309 }
1310
1311 fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
1312 if let hir::StmtKind::Semi(e) = s.kind &&
1313 let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
1314 let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
1315 let Res::Local(hir_id) = seg.res &&
1316 Some(hir_id) == self.closure_local_id {
1317 let (span, arg_str) = if args.len() > 0 {
1318 (args[0].span.shrink_to_lo(), "self, ".to_string())
1319 } else {
1320 let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
1321 (span, "(self)".to_string())
1322 };
1323 self.closure_call_changes.push((span, arg_str));
1324 }
1325 hir::intravisit::walk_stmt(self, s);
1326 }
1327 }
1328
1329 if let Some(hir::Node::ImplItem(
1330 hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
1331 )) = hir.find(self.mir_hir_id()) &&
1332 let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
1333 let mut finder = ExpressionFinder {
1334 capture_span: *capture_kind_span,
1335 closure_change_spans: vec![],
1336 closure_arg_span: None,
1337 in_closure: false,
1338 suggest_arg: String::new(),
1339 closure_local_id: None,
1340 closure_call_changes: vec![],
1341 hir,
1342 };
1343 finder.visit_expr(expr);
1344
1345 if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
1346 return;
1347 }
1348
1349 let mut sugg = vec![];
1350 let sm = self.infcx.tcx.sess.source_map();
1351
1352 if let Some(span) = finder.closure_arg_span {
1353 sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
1354 }
1355 for span in finder.closure_change_spans {
1356 sugg.push((span, "this".to_string()));
1357 }
1358
1359 for (span, suggest) in finder.closure_call_changes {
1360 sugg.push((span, suggest));
1361 }
1362
1363 err.multipart_suggestion_verbose(
1364 "try explicitly pass `&Self` into the Closure as an argument",
1365 sugg,
1366 Applicability::MachineApplicable,
1367 );
1368 }
1369 }
1370
dc9dc135
XL
1371 /// Returns the description of the root place for a conflicting borrow and the full
1372 /// descriptions of the places that caused the conflict.
1373 ///
1374 /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
1375 /// attempted while a shared borrow is live, then this function will return:
04454e1e
FG
1376 /// ```
1377 /// ("x", "", "")
1378 /// # ;
1379 /// ```
dc9dc135
XL
1380 /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
1381 /// a shared borrow of another field `x.y`, then this function will return:
04454e1e
FG
1382 /// ```
1383 /// ("x", "x.z", "x.y")
1384 /// # ;
1385 /// ```
dc9dc135
XL
1386 /// In the more complex union case, where the union is a field of a struct, then if a mutable
1387 /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
1388 /// another field `x.u.y`, then this function will return:
04454e1e
FG
1389 /// ```
1390 /// ("x.u", "x.u.z", "x.u.y")
1391 /// # ;
1392 /// ```
dc9dc135
XL
1393 /// This is used when creating error messages like below:
1394 ///
f9f354fc
XL
1395 /// ```text
1396 /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
1397 /// mutable (via `a.u.s.b`) [E0502]
1398 /// ```
c295e0f8 1399 pub(crate) fn describe_place_for_conflicting_borrow(
dc9dc135 1400 &self,
ba9703b0
XL
1401 first_borrowed_place: Place<'tcx>,
1402 second_borrowed_place: Place<'tcx>,
dc9dc135
XL
1403 ) -> (String, String, String, String) {
1404 // Define a small closure that we can use to check if the type of a place
1405 // is a union.
5869c6ff
XL
1406 let union_ty = |place_base| {
1407 // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`;
1408 // using a type annotation in the closure argument instead leads to a lifetime error.
1409 let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
dc9dc135
XL
1410 ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
1411 };
dc9dc135
XL
1412
1413 // Start with an empty tuple, so we can use the functions on `Option` to reduce some
1414 // code duplication (particularly around returning an empty description in the failure
1415 // case).
1416 Some(())
1417 .filter(|_| {
1418 // If we have a conflicting borrow of the same place, then we don't want to add
1419 // an extraneous "via x.y" to our diagnostics, so filter out this case.
1420 first_borrowed_place != second_borrowed_place
1421 })
1422 .and_then(|_| {
1423 // We're going to want to traverse the first borrowed place to see if we can find
1424 // field access to a union. If we find that, then we will keep the place of the
1425 // union being accessed and the field that was being accessed so we can check the
94222f64 1426 // second borrowed place for the same union and an access to a different field.
5869c6ff 1427 for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
dc9dc135 1428 match elem {
5869c6ff
XL
1429 ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
1430 return Some((place_base, field));
dfeec247
XL
1431 }
1432 _ => {}
dc9dc135
XL
1433 }
1434 }
1435 None
1436 })
1437 .and_then(|(target_base, target_field)| {
1438 // With the place of a union and a field access into it, we traverse the second
94222f64 1439 // borrowed place and look for an access to a different field of the same union.
5869c6ff 1440 for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
dc9dc135 1441 if let ProjectionElem::Field(field, _) = elem {
5869c6ff
XL
1442 if let Some(union_ty) = union_ty(place_base) {
1443 if field != target_field && place_base == target_base {
dc9dc135 1444 return Some((
5869c6ff 1445 self.describe_any_place(place_base),
ba9703b0
XL
1446 self.describe_any_place(first_borrowed_place.as_ref()),
1447 self.describe_any_place(second_borrowed_place.as_ref()),
dc9dc135
XL
1448 union_ty.to_string(),
1449 ));
1450 }
1451 }
1452 }
dc9dc135
XL
1453 }
1454 None
1455 })
1456 .unwrap_or_else(|| {
1457 // If we didn't find a field access into a union, or both places match, then
1458 // only return the description of the first place.
1459 (
ba9703b0 1460 self.describe_any_place(first_borrowed_place.as_ref()),
dc9dc135
XL
1461 "".to_string(),
1462 "".to_string(),
1463 "".to_string(),
1464 )
1465 })
1466 }
1467
1468 /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
1469 ///
1470 /// This means that some data referenced by `borrow` needs to live
1471 /// past the point where the StorageDeadOrDrop of `place` occurs.
1472 /// This is usually interpreted as meaning that `place` has too
1473 /// short a lifetime. (But sometimes it is more useful to report
1474 /// it as a more direct conflict between the execution of a
1475 /// `Drop::drop` with an aliasing borrow.)
f2b60f7d 1476 #[instrument(level = "debug", skip(self))]
c295e0f8 1477 pub(crate) fn report_borrowed_value_does_not_live_long_enough(
dc9dc135
XL
1478 &mut self,
1479 location: Location,
1480 borrow: &BorrowData<'tcx>,
ba9703b0 1481 place_span: (Place<'tcx>, Span),
dc9dc135
XL
1482 kind: Option<WriteKind>,
1483 ) {
dc9dc135 1484 let drop_span = place_span.1;
dfeec247
XL
1485 let root_place =
1486 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
dc9dc135
XL
1487
1488 let borrow_spans = self.retrieve_borrow_spans(borrow);
17df50a5 1489 let borrow_span = borrow_spans.var_or_use_path_span();
dc9dc135 1490
e1599b0c 1491 assert!(root_place.projection.is_empty());
74b04a01 1492 let proper_span = self.body.local_decls[root_place.local].source_info.span;
dc9dc135 1493
9ffffee4 1494 let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
e74abb32 1495
dfeec247 1496 if self.access_place_error_reported.contains(&(
74b04a01 1497 Place { local: root_place.local, projection: root_place_projection },
dfeec247
XL
1498 borrow_span,
1499 )) {
dc9dc135
XL
1500 debug!(
1501 "suppressing access_place error when borrow doesn't live long enough for {:?}",
1502 borrow_span
1503 );
1504 return;
1505 }
1506
dfeec247 1507 self.access_place_error_reported.insert((
74b04a01 1508 Place { local: root_place.local, projection: root_place_projection },
dfeec247
XL
1509 borrow_span,
1510 ));
dc9dc135 1511
dfeec247
XL
1512 let borrowed_local = borrow.borrowed_place.local;
1513 if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
1514 let err =
1515 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
5099ac24 1516 self.buffer_error(err);
dfeec247
XL
1517 return;
1518 }
60c5eb7d 1519
dc9dc135 1520 if let StorageDeadOrDrop::Destructor(dropped_ty) =
416331ca 1521 self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
dc9dc135
XL
1522 {
1523 // If a borrow of path `B` conflicts with drop of `D` (and
1524 // we're not in the uninteresting case where `B` is a
1525 // prefix of `D`), then report this as a more interesting
1526 // destructor conflict.
416331ca 1527 if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
dc9dc135
XL
1528 self.report_borrow_conflicts_with_destructor(
1529 location, borrow, place_span, kind, dropped_ty,
1530 );
1531 return;
1532 }
1533 }
1534
416331ca 1535 let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
dc9dc135
XL
1536
1537 let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
1538 let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
1539
f2b60f7d
FG
1540 debug!(?place_desc, ?explanation);
1541
dc9dc135 1542 let err = match (place_desc, explanation) {
dc9dc135
XL
1543 // If the outlives constraint comes from inside the closure,
1544 // for example:
1545 //
1546 // let x = 0;
1547 // let y = &x;
1548 // Box::new(|| y) as Box<Fn() -> &'static i32>
1549 //
1550 // then just use the normal error. The closure isn't escaping
1551 // and `move` will not help here.
9c376795
FG
1552 (
1553 Some(name),
1554 BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
1555 ) => self.report_escaping_closure_capture(
1556 borrow_spans,
1557 borrow_span,
1558 &RegionName {
1559 name: self.synthesize_region_name(),
1560 source: RegionNameSource::Static,
1561 },
1562 ConstraintCategory::CallArgument(None),
1563 var_or_use_span,
1564 &format!("`{}`", name),
1565 "block",
1566 ),
dc9dc135 1567 (
487cf647 1568 Some(name),
dc9dc135 1569 BorrowExplanation::MustBeValidFor {
ba9703b0 1570 category:
a2a8927a 1571 category @ (ConstraintCategory::Return(_)
923072b8 1572 | ConstraintCategory::CallArgument(_)
ba9703b0 1573 | ConstraintCategory::OpaqueType),
dc9dc135
XL
1574 from_closure: false,
1575 ref region_name,
1576 span,
1577 ..
1578 },
ba9703b0
XL
1579 ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
1580 .report_escaping_closure_capture(
1581 borrow_spans,
1582 borrow_span,
1583 region_name,
1584 category,
e74abb32 1585 span,
ba9703b0 1586 &format!("`{}`", name),
9c376795 1587 "function",
ba9703b0 1588 ),
dc9dc135 1589 (
487cf647 1590 name,
dc9dc135
XL
1591 BorrowExplanation::MustBeValidFor {
1592 category: ConstraintCategory::Assignment,
1593 from_closure: false,
dfeec247
XL
1594 region_name:
1595 RegionName {
064997fb 1596 source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name),
dfeec247
XL
1597 ..
1598 },
dc9dc135
XL
1599 span,
1600 ..
1601 },
487cf647 1602 ) => self.report_escaping_data(borrow_span, &name, upvar_span, upvar_name, span),
dc9dc135
XL
1603 (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
1604 location,
1605 &name,
1606 &borrow,
1607 drop_span,
1608 borrow_spans,
1609 explanation,
1610 ),
1611 (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
1612 location,
1613 &borrow,
1614 drop_span,
1615 borrow_spans,
1616 proper_span,
1617 explanation,
1618 ),
1619 };
1620
5099ac24 1621 self.buffer_error(err);
dc9dc135
XL
1622 }
1623
1624 fn report_local_value_does_not_live_long_enough(
1625 &mut self,
1626 location: Location,
1627 name: &str,
1628 borrow: &BorrowData<'tcx>,
1629 drop_span: Span,
1b1a35ee 1630 borrow_spans: UseSpans<'tcx>,
923072b8 1631 explanation: BorrowExplanation<'tcx>,
5e7ed085 1632 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dc9dc135
XL
1633 debug!(
1634 "report_local_value_does_not_live_long_enough(\
1635 {:?}, {:?}, {:?}, {:?}, {:?}\
1636 )",
1637 location, name, borrow, drop_span, borrow_spans
1638 );
1639
17df50a5 1640 let borrow_span = borrow_spans.var_or_use_path_span();
dc9dc135
XL
1641 if let BorrowExplanation::MustBeValidFor {
1642 category,
1643 span,
1644 ref opt_place_desc,
1645 from_closure: false,
1646 ..
dfeec247
XL
1647 } = explanation
1648 {
dc9dc135
XL
1649 if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1650 borrow,
1651 borrow_span,
1652 span,
1653 category,
1654 opt_place_desc.as_ref(),
1655 ) {
1656 return diag;
1657 }
1658 }
1659
dfeec247 1660 let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name));
dc9dc135
XL
1661
1662 if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
1663 let region_name = annotation.emit(self, &mut err);
1664
1665 err.span_label(
1666 borrow_span,
1667 format!("`{}` would have to be valid for `{}`...", name, region_name),
1668 );
1669
f9f354fc
XL
1670 err.span_label(
1671 drop_span,
1672 format!(
1673 "...but `{}` will be dropped here, when the {} returns",
1674 name,
1675 self.infcx
1676 .tcx
9ffffee4 1677 .opt_item_name(self.mir_def_id().to_def_id())
f9f354fc
XL
1678 .map(|name| format!("function `{}`", name))
1679 .unwrap_or_else(|| {
9ffffee4
FG
1680 match &self.infcx.tcx.def_kind(self.mir_def_id()) {
1681 DefKind::Closure => "enclosing closure",
1682 DefKind::Generator => "enclosing generator",
f9f354fc
XL
1683 kind => bug!("expected closure or generator, found {:?}", kind),
1684 }
1685 .to_string()
1686 })
1687 ),
1688 );
dc9dc135 1689
f9f354fc
XL
1690 err.note(
1691 "functions cannot return a borrow to data owned within the function's scope, \
1692 functions can only return borrows to data passed as arguments",
1693 );
1694 err.note(
1695 "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
1696 references-and-borrowing.html#dangling-references>",
1697 );
dc9dc135
XL
1698
1699 if let BorrowExplanation::MustBeValidFor { .. } = explanation {
1700 } else {
1701 explanation.add_explanation_to_diagnostic(
1702 self.infcx.tcx,
60c5eb7d
XL
1703 &self.body,
1704 &self.local_names,
dc9dc135
XL
1705 &mut err,
1706 "",
1707 None,
136023e0 1708 None,
dc9dc135
XL
1709 );
1710 }
1711 } else {
1712 err.span_label(borrow_span, "borrowed value does not live long enough");
dfeec247 1713 err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
dc9dc135 1714
dfeec247 1715 let within = if borrow_spans.for_generator() { " by generator" } else { "" };
dc9dc135 1716
dfeec247 1717 borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
dc9dc135
XL
1718
1719 explanation.add_explanation_to_diagnostic(
dfeec247
XL
1720 self.infcx.tcx,
1721 &self.body,
1722 &self.local_names,
1723 &mut err,
1724 "",
9ffffee4 1725 Some(borrow_span),
136023e0 1726 None,
dfeec247 1727 );
dc9dc135
XL
1728 }
1729
1730 err
1731 }
1732
1733 fn report_borrow_conflicts_with_destructor(
1734 &mut self,
1735 location: Location,
1736 borrow: &BorrowData<'tcx>,
ba9703b0 1737 (place, drop_span): (Place<'tcx>, Span),
dc9dc135
XL
1738 kind: Option<WriteKind>,
1739 dropped_ty: Ty<'tcx>,
1740 ) {
1741 debug!(
1742 "report_borrow_conflicts_with_destructor(\
1743 {:?}, {:?}, ({:?}, {:?}), {:?}\
1744 )",
1745 location, borrow, place, drop_span, kind,
1746 );
1747
1748 let borrow_spans = self.retrieve_borrow_spans(borrow);
1749 let borrow_span = borrow_spans.var_or_use();
1750
416331ca 1751 let mut err = self.cannot_borrow_across_destructor(borrow_span);
dc9dc135 1752
416331ca 1753 let what_was_dropped = match self.describe_place(place.as_ref()) {
60c5eb7d 1754 Some(name) => format!("`{}`", name),
dc9dc135
XL
1755 None => String::from("temporary value"),
1756 };
1757
416331ca 1758 let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
dc9dc135
XL
1759 Some(borrowed) => format!(
1760 "here, drop of {D} needs exclusive access to `{B}`, \
1761 because the type `{T}` implements the `Drop` trait",
1762 D = what_was_dropped,
1763 T = dropped_ty,
1764 B = borrowed
1765 ),
1766 None => format!(
1767 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
1768 D = what_was_dropped,
1769 T = dropped_ty
1770 ),
1771 };
1772 err.span_label(drop_span, label);
1773
1774 // Only give this note and suggestion if they could be relevant.
1775 let explanation =
1776 self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
1777 match explanation {
1778 BorrowExplanation::UsedLater { .. }
1779 | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1780 err.note("consider using a `let` binding to create a longer lived value");
1781 }
1782 _ => {}
1783 }
1784
60c5eb7d
XL
1785 explanation.add_explanation_to_diagnostic(
1786 self.infcx.tcx,
1787 &self.body,
1788 &self.local_names,
1789 &mut err,
1790 "",
1791 None,
136023e0 1792 None,
60c5eb7d 1793 );
dc9dc135 1794
5099ac24 1795 self.buffer_error(err);
dc9dc135
XL
1796 }
1797
1798 fn report_thread_local_value_does_not_live_long_enough(
1799 &mut self,
1800 drop_span: Span,
1801 borrow_span: Span,
5e7ed085 1802 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dc9dc135
XL
1803 debug!(
1804 "report_thread_local_value_does_not_live_long_enough(\
1805 {:?}, {:?}\
1806 )",
1807 drop_span, borrow_span
1808 );
1809
416331ca 1810 let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
dc9dc135
XL
1811
1812 err.span_label(
1813 borrow_span,
1814 "thread-local variables cannot be borrowed beyond the end of the function",
1815 );
1816 err.span_label(drop_span, "end of enclosing function is here");
1817
1818 err
1819 }
1820
f2b60f7d 1821 #[instrument(level = "debug", skip(self))]
dc9dc135
XL
1822 fn report_temporary_value_does_not_live_long_enough(
1823 &mut self,
1824 location: Location,
1825 borrow: &BorrowData<'tcx>,
1826 drop_span: Span,
1b1a35ee 1827 borrow_spans: UseSpans<'tcx>,
dc9dc135 1828 proper_span: Span,
923072b8 1829 explanation: BorrowExplanation<'tcx>,
5e7ed085 1830 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dfeec247
XL
1831 if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
1832 explanation
1833 {
dc9dc135
XL
1834 if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1835 borrow,
1836 proper_span,
1837 span,
1838 category,
1839 None,
1840 ) {
1841 return diag;
1842 }
1843 }
1844
416331ca 1845 let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
487cf647 1846 err.span_label(proper_span, "creates a temporary value which is freed while still in use");
dfeec247 1847 err.span_label(drop_span, "temporary value is freed at the end of this statement");
dc9dc135
XL
1848
1849 match explanation {
1850 BorrowExplanation::UsedLater(..)
1851 | BorrowExplanation::UsedLaterInLoop(..)
1852 | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1853 // Only give this note and suggestion if it could be relevant.
064997fb
FG
1854 let sm = self.infcx.tcx.sess.source_map();
1855 let mut suggested = false;
1856 let msg = "consider using a `let` binding to create a longer lived value";
1857
1858 /// We check that there's a single level of block nesting to ensure always correct
1859 /// suggestions. If we don't, then we only provide a free-form message to avoid
9c376795 1860 /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
064997fb
FG
1861 /// We could expand the analysis to suggest hoising all of the relevant parts of
1862 /// the users' code to make the code compile, but that could be too much.
1863 struct NestedStatementVisitor {
1864 span: Span,
1865 current: usize,
1866 found: usize,
1867 }
1868
1869 impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
1870 fn visit_block(&mut self, block: &hir::Block<'tcx>) {
1871 self.current += 1;
1872 walk_block(self, block);
1873 self.current -= 1;
1874 }
1875 fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
1876 if self.span == expr.span {
1877 self.found = self.current;
1878 }
1879 walk_expr(self, expr);
1880 }
1881 }
1882 let source_info = self.body.source_info(location);
1883 if let Some(scope) = self.body.source_scopes.get(source_info.scope)
1884 && let ClearCrossCrate::Set(scope_data) = &scope.local_data
1885 && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
1886 && let Some(id) = node.body_id()
1887 && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
1888 {
1889 for stmt in block.stmts {
1890 let mut visitor = NestedStatementVisitor {
1891 span: proper_span,
1892 current: 0,
1893 found: 0,
1894 };
1895 visitor.visit_stmt(stmt);
1896 if visitor.found == 0
1897 && stmt.span.contains(proper_span)
1898 && let Some(p) = sm.span_to_margin(stmt.span)
1899 && let Ok(s) = sm.span_to_snippet(proper_span)
1900 {
1901 let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
1902 err.multipart_suggestion_verbose(
1903 msg,
1904 vec![
1905 (stmt.span.shrink_to_lo(), addition),
1906 (proper_span, "binding".to_string()),
1907 ],
1908 Applicability::MaybeIncorrect,
1909 );
1910 suggested = true;
1911 break;
1912 }
1913 }
1914 }
1915 if !suggested {
1916 err.note(msg);
1917 }
dc9dc135
XL
1918 }
1919 _ => {}
1920 }
60c5eb7d
XL
1921 explanation.add_explanation_to_diagnostic(
1922 self.infcx.tcx,
1923 &self.body,
1924 &self.local_names,
1925 &mut err,
1926 "",
1927 None,
136023e0 1928 None,
60c5eb7d 1929 );
dc9dc135 1930
dfeec247 1931 let within = if borrow_spans.for_generator() { " by generator" } else { "" };
dc9dc135 1932
dfeec247 1933 borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
dc9dc135
XL
1934
1935 err
1936 }
1937
1938 fn try_report_cannot_return_reference_to_local(
1939 &self,
1940 borrow: &BorrowData<'tcx>,
1941 borrow_span: Span,
1942 return_span: Span,
923072b8 1943 category: ConstraintCategory<'tcx>,
dc9dc135 1944 opt_place_desc: Option<&String>,
5e7ed085 1945 ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
dc9dc135 1946 let return_kind = match category {
f035d41b 1947 ConstraintCategory::Return(_) => "return",
dc9dc135
XL
1948 ConstraintCategory::Yield => "yield",
1949 _ => return None,
1950 };
1951
1952 // FIXME use a better heuristic than Spans
dfeec247
XL
1953 let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span {
1954 "reference to"
1955 } else {
1956 "value referencing"
1957 };
dc9dc135
XL
1958
1959 let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
e74abb32
XL
1960 let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
1961 match self.body.local_kind(local) {
dfeec247
XL
1962 LocalKind::ReturnPointer | LocalKind::Temp => {
1963 bug!("temporary or return pointer with a name")
1964 }
e74abb32 1965 LocalKind::Var => "local variable ",
17df50a5
XL
1966 LocalKind::Arg
1967 if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
1968 {
e74abb32
XL
1969 "variable captured by `move` "
1970 }
dfeec247 1971 LocalKind::Arg => "function parameter ",
dc9dc135 1972 }
e74abb32
XL
1973 } else {
1974 "local data "
dc9dc135
XL
1975 };
1976 (
1977 format!("{}`{}`", local_kind, place_desc),
1978 format!("`{}` is borrowed here", place_desc),
1979 )
1980 } else {
dfeec247
XL
1981 let root_place =
1982 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
1983 let local = root_place.local;
74b04a01 1984 match self.body.local_kind(local) {
dfeec247
XL
1985 LocalKind::ReturnPointer | LocalKind::Temp => {
1986 ("temporary value".to_string(), "temporary value created here".to_string())
1987 }
dc9dc135
XL
1988 LocalKind::Arg => (
1989 "function parameter".to_string(),
1990 "function parameter borrowed here".to_string(),
1991 ),
dfeec247
XL
1992 LocalKind::Var => {
1993 ("local binding".to_string(), "local binding introduced here".to_string())
1994 }
dc9dc135
XL
1995 }
1996 };
1997
416331ca 1998 let mut err = self.cannot_return_reference_to_local(
dc9dc135
XL
1999 return_span,
2000 return_kind,
2001 reference_desc,
2002 &place_desc,
dc9dc135
XL
2003 );
2004
2005 if return_span != borrow_span {
2006 err.span_label(borrow_span, note);
6a06907d
XL
2007
2008 let tcx = self.infcx.tcx;
6a06907d
XL
2009
2010 let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
2011 let return_ty = tcx.erase_regions(return_ty);
2012
2013 // to avoid panics
064997fb
FG
2014 if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
2015 && self
136023e0 2016 .infcx
487cf647 2017 .type_implements_trait(iter_trait, [return_ty], self.param_env)
136023e0 2018 .must_apply_modulo_regions()
064997fb
FG
2019 {
2020 err.span_suggestion_hidden(
2021 return_span.shrink_to_hi(),
2022 "use `.collect()` to allocate the iterator",
2023 ".collect::<Vec<_>>()",
2024 Applicability::MaybeIncorrect,
2025 );
6a06907d 2026 }
dc9dc135
XL
2027 }
2028
2029 Some(err)
2030 }
2031
9c376795 2032 #[instrument(level = "debug", skip(self))]
dc9dc135
XL
2033 fn report_escaping_closure_capture(
2034 &mut self,
1b1a35ee 2035 use_span: UseSpans<'tcx>,
dc9dc135
XL
2036 var_span: Span,
2037 fr_name: &RegionName,
923072b8 2038 category: ConstraintCategory<'tcx>,
dc9dc135
XL
2039 constraint_span: Span,
2040 captured_var: &str,
9c376795 2041 scope: &str,
5e7ed085 2042 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dc9dc135 2043 let tcx = self.infcx.tcx;
e74abb32 2044 let args_span = use_span.args_or_use();
dc9dc135 2045
94222f64
XL
2046 let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
2047 Ok(string) => {
e1599b0c 2048 if string.starts_with("async ") {
94222f64 2049 let pos = args_span.lo() + BytePos(6);
923072b8 2050 (args_span.with_lo(pos).with_hi(pos), "move ")
e1599b0c 2051 } else if string.starts_with("async|") {
94222f64 2052 let pos = args_span.lo() + BytePos(5);
923072b8 2053 (args_span.with_lo(pos).with_hi(pos), " move")
e1599b0c 2054 } else {
923072b8 2055 (args_span.shrink_to_lo(), "move ")
94222f64 2056 }
dfeec247 2057 }
923072b8 2058 Err(_) => (args_span, "move |<args>| <body>"),
dc9dc135 2059 };
e74abb32
XL
2060 let kind = match use_span.generator_kind() {
2061 Some(generator_kind) => match generator_kind {
2062 GeneratorKind::Async(async_kind) => match async_kind {
2063 AsyncGeneratorKind::Block => "async block",
2064 AsyncGeneratorKind::Closure => "async closure",
74b04a01 2065 _ => bug!("async block/closure expected, but async function found."),
e74abb32
XL
2066 },
2067 GeneratorKind::Gen => "generator",
dfeec247 2068 },
e74abb32
XL
2069 None => "closure",
2070 };
ba9703b0 2071
9c376795
FG
2072 let mut err = self.cannot_capture_in_long_lived_closure(
2073 args_span,
2074 kind,
2075 captured_var,
2076 var_span,
2077 scope,
2078 );
94222f64
XL
2079 err.span_suggestion_verbose(
2080 sugg_span,
e74abb32
XL
2081 &format!(
2082 "to force the {} to take ownership of {} (and any \
2083 other referenced variables), use the `move` keyword",
dfeec247 2084 kind, captured_var
e74abb32 2085 ),
dc9dc135
XL
2086 suggestion,
2087 Applicability::MachineApplicable,
2088 );
2089
5869c6ff 2090 match category {
f035d41b 2091 ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
5869c6ff
XL
2092 let msg = format!("{} is returned here", kind);
2093 err.span_note(constraint_span, &msg);
ba9703b0 2094 }
923072b8 2095 ConstraintCategory::CallArgument(_) => {
dc9dc135 2096 fr_name.highlight_region_name(&mut err);
5869c6ff
XL
2097 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
2098 err.note(
2099 "async blocks are not executed immediately and must either take a \
9c376795 2100 reference or ownership of outside variables they use",
5869c6ff
XL
2101 );
2102 } else {
9c376795 2103 let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
5869c6ff
XL
2104 err.span_note(constraint_span, &msg);
2105 }
dc9dc135 2106 }
dfeec247
XL
2107 _ => bug!(
2108 "report_escaping_closure_capture called with unexpected constraint \
74b04a01 2109 category: `{:?}`",
dfeec247
XL
2110 category
2111 ),
5869c6ff
XL
2112 }
2113
dc9dc135
XL
2114 err
2115 }
2116
2117 fn report_escaping_data(
2118 &mut self,
2119 borrow_span: Span,
2120 name: &Option<String>,
2121 upvar_span: Span,
064997fb 2122 upvar_name: Symbol,
dc9dc135 2123 escape_span: Span,
5e7ed085 2124 ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
dc9dc135
XL
2125 let tcx = self.infcx.tcx;
2126
9ffffee4 2127 let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());
dc9dc135 2128
dfeec247
XL
2129 let mut err =
2130 borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
dc9dc135
XL
2131
2132 err.span_label(
2133 upvar_span,
74b04a01 2134 format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from),
dc9dc135
XL
2135 );
2136
dfeec247 2137 err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from));
dc9dc135
XL
2138
2139 if let Some(name) = name {
2140 err.span_label(
2141 escape_span,
2142 format!("reference to `{}` escapes the {} body here", name, escapes_from),
2143 );
2144 } else {
2145 err.span_label(
2146 escape_span,
2147 format!("reference escapes the {} body here", escapes_from),
2148 );
2149 }
2150
2151 err
2152 }
2153
136023e0
XL
2154 fn get_moved_indexes(
2155 &mut self,
2156 location: Location,
2157 mpi: MovePathIndex,
2158 ) -> (Vec<MoveSite>, Vec<Location>) {
923072b8
FG
2159 fn predecessor_locations<'tcx, 'a>(
2160 body: &'a mir::Body<'tcx>,
f9f354fc 2161 location: Location,
923072b8 2162 ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
f9f354fc 2163 if location.statement_index == 0 {
064997fb 2164 let predecessors = body.basic_blocks.predecessors()[location.block].to_vec();
f9f354fc
XL
2165 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
2166 } else {
2167 Either::Right(std::iter::once(Location {
2168 statement_index: location.statement_index - 1,
2169 ..location
2170 }))
2171 }
2172 }
2173
c295e0f8
XL
2174 let mut mpis = vec![mpi];
2175 let move_paths = &self.move_data.move_paths;
2176 mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
2177
dc9dc135 2178 let mut stack = Vec::new();
c295e0f8
XL
2179 let mut back_edge_stack = Vec::new();
2180
2181 predecessor_locations(self.body, location).for_each(|predecessor| {
9c376795 2182 if location.dominates(predecessor, self.dominators()) {
c295e0f8
XL
2183 back_edge_stack.push(predecessor)
2184 } else {
2185 stack.push(predecessor);
2186 }
2187 });
2188
2189 let mut reached_start = false;
2190
2191 /* Check if the mpi is initialized as an argument */
2192 let mut is_argument = false;
2193 for arg in self.body.args_iter() {
2194 let path = self.move_data.rev_lookup.find_local(arg);
2195 if mpis.contains(&path) {
2196 is_argument = true;
2197 }
2198 }
dc9dc135
XL
2199
2200 let mut visited = FxHashSet::default();
136023e0
XL
2201 let mut move_locations = FxHashSet::default();
2202 let mut reinits = vec![];
dc9dc135
XL
2203 let mut result = vec![];
2204
c295e0f8 2205 let mut dfs_iter = |result: &mut Vec<MoveSite>, location: Location, is_back_edge: bool| {
dc9dc135
XL
2206 debug!(
2207 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
2208 location, is_back_edge
2209 );
2210
2211 if !visited.insert(location) {
c295e0f8 2212 return true;
dc9dc135
XL
2213 }
2214
2215 // check for moves
dfeec247
XL
2216 let stmt_kind =
2217 self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
dc9dc135
XL
2218 if let Some(StatementKind::StorageDead(..)) = stmt_kind {
2219 // this analysis only tries to find moves explicitly
2220 // written by the user, so we ignore the move-outs
2221 // created by `StorageDead` and at the beginning
2222 // of a function.
2223 } else {
2224 // If we are found a use of a.b.c which was in error, then we want to look for
2225 // moves not only of a.b.c but also a.b and a.
2226 //
2227 // Note that the moves data already includes "parent" paths, so we don't have to
2228 // worry about the other case: that is, if there is a move of a.b.c, it is already
2229 // marked as a move of a.b and a as well, so we will generate the correct errors
2230 // there.
dc9dc135
XL
2231 for moi in &self.move_data.loc_map[location] {
2232 debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
1b1a35ee
XL
2233 let path = self.move_data.moves[*moi].path;
2234 if mpis.contains(&path) {
2235 debug!(
2236 "report_use_of_moved_or_uninitialized: found {:?}",
2237 move_paths[path].place
2238 );
dfeec247 2239 result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
136023e0 2240 move_locations.insert(location);
dc9dc135
XL
2241
2242 // Strictly speaking, we could continue our DFS here. There may be
2243 // other moves that can reach the point of error. But it is kind of
2244 // confusing to highlight them.
2245 //
2246 // Example:
2247 //
2248 // ```
2249 // let a = vec![];
2250 // let b = a;
2251 // let c = a;
2252 // drop(a); // <-- current point of error
2253 // ```
2254 //
2255 // Because we stop the DFS here, we only highlight `let c = a`,
2256 // and not `let b = a`. We will of course also report an error at
2257 // `let c = a` which highlights `let b = a` as the move.
c295e0f8 2258 return true;
dc9dc135
XL
2259 }
2260 }
2261 }
2262
2263 // check for inits
2264 let mut any_match = false;
c295e0f8
XL
2265 for ii in &self.move_data.init_loc_map[location] {
2266 let init = self.move_data.inits[*ii];
2267 match init.kind {
2268 InitKind::Deep | InitKind::NonPanicPathOnly => {
2269 if mpis.contains(&init.path) {
2270 any_match = true;
2271 }
dc9dc135 2272 }
c295e0f8
XL
2273 InitKind::Shallow => {
2274 if mpi == init.path {
2275 any_match = true;
2276 }
2277 }
2278 }
2279 }
dc9dc135 2280 if any_match {
136023e0 2281 reinits.push(location);
c295e0f8 2282 return true;
dc9dc135 2283 }
c295e0f8
XL
2284 return false;
2285 };
dc9dc135 2286
c295e0f8
XL
2287 while let Some(location) = stack.pop() {
2288 if dfs_iter(&mut result, location, false) {
2289 continue;
2290 }
2291
2292 let mut has_predecessor = false;
2293 predecessor_locations(self.body, location).for_each(|predecessor| {
9c376795 2294 if location.dominates(predecessor, self.dominators()) {
c295e0f8
XL
2295 back_edge_stack.push(predecessor)
2296 } else {
2297 stack.push(predecessor);
2298 }
2299 has_predecessor = true;
2300 });
2301
2302 if !has_predecessor {
2303 reached_start = true;
2304 }
2305 }
2306 if (is_argument || !reached_start) && result.is_empty() {
2307 /* Process back edges (moves in future loop iterations) only if
2308 the move path is definitely initialized upon loop entry,
2309 to avoid spurious "in previous iteration" errors.
2310 During DFS, if there's a path from the error back to the start
2311 of the function with no intervening init or move, then the
2312 move path may be uninitialized at loop entry.
2313 */
2314 while let Some(location) = back_edge_stack.pop() {
2315 if dfs_iter(&mut result, location, true) {
2316 continue;
2317 }
2318
2319 predecessor_locations(self.body, location)
2320 .for_each(|predecessor| back_edge_stack.push(predecessor));
2321 }
dc9dc135
XL
2322 }
2323
136023e0
XL
2324 // Check if we can reach these reinits from a move location.
2325 let reinits_reachable = reinits
2326 .into_iter()
2327 .filter(|reinit| {
2328 let mut visited = FxHashSet::default();
2329 let mut stack = vec![*reinit];
2330 while let Some(location) = stack.pop() {
2331 if !visited.insert(location) {
2332 continue;
2333 }
2334 if move_locations.contains(&location) {
2335 return true;
2336 }
2337 stack.extend(predecessor_locations(self.body, location));
2338 }
2339 false
2340 })
2341 .collect::<Vec<Location>>();
2342 (result, reinits_reachable)
dc9dc135
XL
2343 }
2344
c295e0f8 2345 pub(crate) fn report_illegal_mutation_of_borrowed(
dc9dc135
XL
2346 &mut self,
2347 location: Location,
ba9703b0 2348 (place, span): (Place<'tcx>, Span),
dc9dc135
XL
2349 loan: &BorrowData<'tcx>,
2350 ) {
2351 let loan_spans = self.retrieve_borrow_spans(loan);
2352 let loan_span = loan_spans.args_or_use();
2353
ba9703b0 2354 let descr_place = self.describe_any_place(place.as_ref());
dc9dc135 2355 if loan.kind == BorrowKind::Shallow {
ba9703b0 2356 if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
60c5eb7d
XL
2357 let mut err = self.cannot_mutate_in_immutable_section(
2358 span,
2359 loan_span,
ba9703b0 2360 &descr_place,
60c5eb7d
XL
2361 section,
2362 "assign",
2363 );
2364 loan_spans.var_span_label(
2365 &mut err,
2366 format!("borrow occurs due to use{}", loan_spans.describe()),
17df50a5 2367 loan.kind.describe_mutability(),
60c5eb7d 2368 );
dc9dc135 2369
5099ac24 2370 self.buffer_error(err);
dc9dc135 2371
60c5eb7d
XL
2372 return;
2373 }
dc9dc135
XL
2374 }
2375
ba9703b0 2376 let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
dc9dc135 2377
17df50a5
XL
2378 loan_spans.var_span_label(
2379 &mut err,
2380 format!("borrow occurs due to use{}", loan_spans.describe()),
2381 loan.kind.describe_mutability(),
2382 );
dfeec247
XL
2383
2384 self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
2385 self.infcx.tcx,
2386 &self.body,
2387 &self.local_names,
dc9dc135 2388 &mut err,
dfeec247
XL
2389 "",
2390 None,
136023e0 2391 None,
dc9dc135
XL
2392 );
2393
6a06907d
XL
2394 self.explain_deref_coercion(loan, &mut err);
2395
5099ac24 2396 self.buffer_error(err);
dc9dc135
XL
2397 }
2398
5e7ed085 2399 fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
6a06907d
XL
2400 let tcx = self.infcx.tcx;
2401 if let (
2402 Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
2403 Some((method_did, method_substs)),
2404 ) = (
2405 &self.body[loan.reserve_location.block].terminator,
c295e0f8 2406 rustc_const_eval::util::find_self_call(
6a06907d
XL
2407 tcx,
2408 self.body,
2409 loan.assigned_place.local,
2410 loan.reserve_location.block,
2411 ),
2412 ) {
2413 if tcx.is_diagnostic_item(sym::deref_method, method_did) {
2414 let deref_target =
2415 tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
2416 Instance::resolve(tcx, self.param_env, deref_target, method_substs)
2417 .transpose()
2418 });
2419 if let Some(Ok(instance)) = deref_target {
2420 let deref_target_ty = instance.ty(tcx, self.param_env);
2421 err.note(&format!(
2422 "borrow occurs due to deref coercion to `{}`",
2423 deref_target_ty
2424 ));
2425 err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
2426 }
2427 }
2428 }
2429 }
2430
dc9dc135
XL
2431 /// Reports an illegal reassignment; for example, an assignment to
2432 /// (part of) a non-`mut` local that occurs potentially after that
2433 /// local has already been initialized. `place` is the path being
2434 /// assigned; `err_place` is a place providing a reason why
2435 /// `place` is not mutable (e.g., the non-`mut` local `x` in an
2436 /// assignment to `x.f`).
c295e0f8 2437 pub(crate) fn report_illegal_reassignment(
dc9dc135
XL
2438 &mut self,
2439 _location: Location,
ba9703b0 2440 (place, span): (Place<'tcx>, Span),
dc9dc135 2441 assigned_span: Span,
ba9703b0 2442 err_place: Place<'tcx>,
dc9dc135 2443 ) {
60c5eb7d
XL
2444 let (from_arg, local_decl, local_name) = match err_place.as_local() {
2445 Some(local) => (
2446 self.body.local_kind(local) == LocalKind::Arg,
2447 Some(&self.body.local_decls[local]),
2448 self.local_names[local],
2449 ),
2450 None => (false, None, None),
dc9dc135
XL
2451 };
2452
2453 // If root local is initialized immediately (everything apart from let
2454 // PATTERN;) then make the error refer to that local, rather than the
2455 // place being assigned later.
2456 let (place_description, assigned_span) = match local_decl {
ba9703b0 2457 Some(LocalDecl {
dfeec247 2458 local_info:
f9f354fc 2459 Some(box LocalInfo::User(
ba9703b0
XL
2460 ClearCrossCrate::Clear
2461 | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
2462 opt_match_place: None,
2463 ..
2464 })),
f9f354fc
XL
2465 ))
2466 | Some(box LocalInfo::StaticRef { .. })
2467 | None,
dc9dc135
XL
2468 ..
2469 })
ba9703b0
XL
2470 | None => (self.describe_any_place(place.as_ref()), assigned_span),
2471 Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span),
dc9dc135
XL
2472 };
2473
ba9703b0 2474 let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg);
dc9dc135
XL
2475 let msg = if from_arg {
2476 "cannot assign to immutable argument"
2477 } else {
2478 "cannot assign twice to immutable variable"
2479 };
04454e1e
FG
2480 if span != assigned_span && !from_arg {
2481 err.span_label(assigned_span, format!("first assignment to {}", place_description));
dc9dc135 2482 }
5e7ed085
FG
2483 if let Some(decl) = local_decl
2484 && let Some(name) = local_name
2485 && decl.can_be_made_mutable()
2486 {
2487 err.span_suggestion(
2488 decl.source_info.span,
2489 "consider making this binding mutable",
2490 format!("mut {}", name),
2491 Applicability::MachineApplicable,
2492 );
dc9dc135
XL
2493 }
2494 err.span_label(span, msg);
5099ac24 2495 self.buffer_error(err);
dc9dc135
XL
2496 }
2497
74b04a01 2498 fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
dc9dc135 2499 let tcx = self.infcx.tcx;
04454e1e
FG
2500 let (kind, _place_ty) = place.projection.iter().fold(
2501 (LocalStorageDead, PlaceTy::from_ty(self.body.local_decls[place.local].ty)),
2502 |(kind, place_ty), &elem| {
2503 (
2504 match elem {
2505 ProjectionElem::Deref => match kind {
2506 StorageDeadOrDrop::LocalStorageDead
2507 | StorageDeadOrDrop::BoxedStorageDead => {
2508 assert!(
2509 place_ty.ty.is_box(),
2510 "Drop of value behind a reference or raw pointer"
2511 );
2512 StorageDeadOrDrop::BoxedStorageDead
2513 }
2514 StorageDeadOrDrop::Destructor(_) => kind,
2515 },
2b03887a
FG
2516 ProjectionElem::OpaqueCast { .. }
2517 | ProjectionElem::Field(..)
2518 | ProjectionElem::Downcast(..) => {
04454e1e
FG
2519 match place_ty.ty.kind() {
2520 ty::Adt(def, _) if def.has_dtor(tcx) => {
2521 // Report the outermost adt with a destructor
2522 match kind {
2523 StorageDeadOrDrop::Destructor(_) => kind,
2524 StorageDeadOrDrop::LocalStorageDead
2525 | StorageDeadOrDrop::BoxedStorageDead => {
2526 StorageDeadOrDrop::Destructor(place_ty.ty)
2527 }
dc9dc135
XL
2528 }
2529 }
04454e1e 2530 _ => kind,
dc9dc135 2531 }
dc9dc135 2532 }
04454e1e
FG
2533 ProjectionElem::ConstantIndex { .. }
2534 | ProjectionElem::Subslice { .. }
2535 | ProjectionElem::Index(_) => kind,
2536 },
2537 place_ty.projection_ty(tcx, elem),
2538 )
2539 },
2540 );
2541 kind
dc9dc135
XL
2542 }
2543
60c5eb7d 2544 /// Describe the reason for the fake borrow that was assigned to `place`.
ba9703b0
XL
2545 fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> {
2546 use rustc_middle::mir::visit::Visitor;
2547 struct FakeReadCauseFinder<'tcx> {
2548 place: Place<'tcx>,
60c5eb7d
XL
2549 cause: Option<FakeReadCause>,
2550 }
ba9703b0 2551 impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
60c5eb7d
XL
2552 fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
2553 match statement {
cdc7bbd5 2554 Statement { kind: StatementKind::FakeRead(box (cause, place)), .. }
ba9703b0 2555 if *place == self.place =>
dfeec247 2556 {
60c5eb7d
XL
2557 self.cause = Some(*cause);
2558 }
2559 _ => (),
2560 }
2561 }
2562 }
2563 let mut visitor = FakeReadCauseFinder { place, cause: None };
ba9703b0 2564 visitor.visit_body(&self.body);
60c5eb7d
XL
2565 match visitor.cause {
2566 Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
2567 Some(FakeReadCause::ForIndex) => Some("indexing expression"),
2568 _ => None,
2569 }
2570 }
2571
dc9dc135
XL
2572 /// Annotate argument and return type of function and closure with (synthesized) lifetime for
2573 /// borrow of local value that does not live long enough.
2574 fn annotate_argument_and_return_for_borrow(
2575 &self,
2576 borrow: &BorrowData<'tcx>,
2577 ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2578 // Define a fallback for when we can't match a closure.
2579 let fallback = || {
29967ef6 2580 let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
dc9dc135
XL
2581 if is_closure {
2582 None
2583 } else {
9ffffee4 2584 let ty = self.infcx.tcx.type_of(self.mir_def_id()).subst_identity();
1b1a35ee 2585 match ty.kind() {
f9f354fc 2586 ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
064997fb 2587 self.mir_def_id(),
9ffffee4 2588 self.infcx.tcx.fn_sig(self.mir_def_id()).subst_identity(),
f9f354fc 2589 ),
dc9dc135
XL
2590 _ => None,
2591 }
2592 }
2593 };
2594
2595 // In order to determine whether we need to annotate, we need to check whether the reserve
2596 // place was an assignment into a temporary.
2597 //
2598 // If it was, we check whether or not that temporary is eventually assigned into the return
2599 // place. If it was, we can add annotations about the function's return type and arguments
2600 // and it'll make sense.
2601 let location = borrow.reserve_location;
dfeec247 2602 debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
487cf647 2603 if let Some(Statement { kind: StatementKind::Assign(box (reservation, _)), .. }) =
dfeec247 2604 &self.body[location.block].statements.get(location.statement_index)
dc9dc135 2605 {
dfeec247 2606 debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
dc9dc135 2607 // Check that the initial assignment of the reserve location is into a temporary.
e74abb32
XL
2608 let mut target = match reservation.as_local() {
2609 Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
dc9dc135
XL
2610 _ => return None,
2611 };
2612
2613 // Next, look through the rest of the block, checking if we are assigning the
2614 // `target` (that is, the place that contains our borrow) to anything.
2615 let mut annotated_closure = None;
dfeec247 2616 for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
dc9dc135
XL
2617 debug!(
2618 "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
2619 target, stmt
2620 );
dfeec247 2621 if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
e74abb32
XL
2622 if let Some(assigned_to) = place.as_local() {
2623 debug!(
2624 "annotate_argument_and_return_for_borrow: assigned_to={:?} \
2625 rvalue={:?}",
2626 assigned_to, rvalue
2627 );
2628 // Check if our `target` was captured by a closure.
2629 if let Rvalue::Aggregate(
2630 box AggregateKind::Closure(def_id, substs),
487cf647
FG
2631 operands,
2632 ) = rvalue
e74abb32 2633 {
9ffffee4 2634 let def_id = def_id.expect_local();
e74abb32 2635 for operand in operands {
5e7ed085
FG
2636 let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
2637 continue;
e74abb32
XL
2638 };
2639 debug!(
2640 "annotate_argument_and_return_for_borrow: assigned_from={:?}",
dc9dc135 2641 assigned_from
e74abb32 2642 );
dc9dc135 2643
e74abb32 2644 // Find the local from the operand.
5e7ed085
FG
2645 let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
2646 continue;
e74abb32 2647 };
dc9dc135 2648
e74abb32
XL
2649 if assigned_from_local != target {
2650 continue;
2651 }
dc9dc135 2652
e74abb32
XL
2653 // If a closure captured our `target` and then assigned
2654 // into a place then we should annotate the closure in
2655 // case it ends up being assigned into the return place.
ba9703b0 2656 annotated_closure =
9ffffee4 2657 self.annotate_fn_sig(def_id, substs.as_closure().sig());
e74abb32
XL
2658 debug!(
2659 "annotate_argument_and_return_for_borrow: \
2660 annotated_closure={:?} assigned_from_local={:?} \
2661 assigned_to={:?}",
2662 annotated_closure, assigned_from_local, assigned_to
2663 );
2664
2665 if assigned_to == mir::RETURN_PLACE {
2666 // If it was assigned directly into the return place, then
2667 // return now.
2668 return annotated_closure;
2669 } else {
2670 // Otherwise, update the target.
2671 target = assigned_to;
2672 }
dc9dc135 2673 }
dc9dc135 2674
e74abb32
XL
2675 // If none of our closure's operands matched, then skip to the next
2676 // statement.
2677 continue;
2678 }
dc9dc135 2679
e74abb32
XL
2680 // Otherwise, look at other types of assignment.
2681 let assigned_from = match rvalue {
2682 Rvalue::Ref(_, _, assigned_from) => assigned_from,
2683 Rvalue::Use(operand) => match operand {
2684 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2685 assigned_from
2686 }
2687 _ => continue,
2688 },
dc9dc135 2689 _ => continue,
e74abb32
XL
2690 };
2691 debug!(
2692 "annotate_argument_and_return_for_borrow: \
2693 assigned_from={:?}",
2694 assigned_from,
2695 );
dc9dc135 2696
e74abb32 2697 // Find the local from the rvalue.
5e7ed085 2698 let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { continue };
e74abb32
XL
2699 debug!(
2700 "annotate_argument_and_return_for_borrow: \
2701 assigned_from_local={:?}",
2702 assigned_from_local,
2703 );
dc9dc135 2704
e74abb32
XL
2705 // Check if our local matches the target - if so, we've assigned our
2706 // borrow to a new place.
2707 if assigned_from_local != target {
2708 continue;
2709 }
dc9dc135 2710
e74abb32
XL
2711 // If we assigned our `target` into a new place, then we should
2712 // check if it was the return place.
2713 debug!(
2714 "annotate_argument_and_return_for_borrow: \
2715 assigned_from_local={:?} assigned_to={:?}",
2716 assigned_from_local, assigned_to
2717 );
2718 if assigned_to == mir::RETURN_PLACE {
2719 // If it was then return the annotated closure if there was one,
2720 // else, annotate this function.
2721 return annotated_closure.or_else(fallback);
2722 }
dc9dc135 2723
e74abb32
XL
2724 // If we didn't assign into the return place, then we just update
2725 // the target.
2726 target = assigned_to;
2727 }
dc9dc135
XL
2728 }
2729 }
2730
2731 // Check the terminator if we didn't find anything in the statements.
2732 let terminator = &self.body[location.block].terminator();
2733 debug!(
2734 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
2735 target, terminator
2736 );
923072b8 2737 if let TerminatorKind::Call { destination, target: Some(_), args, .. } =
dfeec247 2738 &terminator.kind
dc9dc135 2739 {
923072b8 2740 if let Some(assigned_to) = destination.as_local() {
dc9dc135 2741 debug!(
e74abb32
XL
2742 "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
2743 assigned_to, args
dc9dc135 2744 );
e74abb32 2745 for operand in args {
5e7ed085
FG
2746 let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
2747 continue;
e74abb32 2748 };
dc9dc135 2749 debug!(
e74abb32
XL
2750 "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2751 assigned_from,
dc9dc135
XL
2752 );
2753
e74abb32
XL
2754 if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
2755 debug!(
2756 "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
2757 assigned_from_local,
2758 );
2759
2760 if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
2761 return annotated_closure.or_else(fallback);
2762 }
dc9dc135
XL
2763 }
2764 }
2765 }
2766 }
2767 }
2768
2769 // If we haven't found an assignment into the return place, then we need not add
2770 // any annotations.
2771 debug!("annotate_argument_and_return_for_borrow: none found");
2772 None
2773 }
2774
2775 /// Annotate the first argument and return type of a function signature if they are
2776 /// references.
2777 fn annotate_fn_sig(
2778 &self,
064997fb 2779 did: LocalDefId,
dc9dc135
XL
2780 sig: ty::PolyFnSig<'tcx>,
2781 ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2782 debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
064997fb
FG
2783 let is_closure = self.infcx.tcx.is_closure(did.to_def_id());
2784 let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
dc9dc135
XL
2785 let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
2786
2787 // We need to work out which arguments to highlight. We do this by looking
2788 // at the return type, where there are three cases:
2789 //
2790 // 1. If there are named arguments, then we should highlight the return type and
2791 // highlight any of the arguments that are also references with that lifetime.
2792 // If there are no arguments that have the same lifetime as the return type,
2793 // then don't highlight anything.
2794 // 2. The return type is a reference with an anonymous lifetime. If this is
2795 // the case, then we can take advantage of (and teach) the lifetime elision
2796 // rules.
2797 //
2798 // We know that an error is being reported. So the arguments and return type
2799 // must satisfy the elision rules. Therefore, if there is a single argument
2800 // then that means the return type and first (and only) argument have the same
2801 // lifetime and the borrow isn't meeting that, we can highlight the argument
2802 // and return type.
2803 //
2804 // If there are multiple arguments then the first argument must be self (else
2805 // it would not satisfy the elision rules), so we can highlight self and the
2806 // return type.
2807 // 3. The return type is not a reference. In this case, we don't highlight
2808 // anything.
2809 let return_ty = sig.output();
1b1a35ee 2810 match return_ty.skip_binder().kind() {
dc9dc135
XL
2811 ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
2812 // This is case 1 from above, return type is a named reference so we need to
2813 // search for relevant arguments.
2814 let mut arguments = Vec::new();
2815 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
1b1a35ee 2816 if let ty::Ref(argument_region, _, _) = argument.kind() {
dc9dc135 2817 if argument_region == return_region {
ba9703b0 2818 // Need to use the `rustc_middle::ty` types to compare against the
dfeec247 2819 // `return_region`. Then use the `rustc_hir` type to get only
dc9dc135 2820 // the lifetime span.
9c376795 2821 if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
dc9dc135
XL
2822 // With access to the lifetime, we can get
2823 // the span of it.
487cf647 2824 arguments.push((*argument, lifetime.ident.span));
dc9dc135
XL
2825 } else {
2826 bug!("ty type is a ref but hir type is not");
2827 }
2828 }
2829 }
2830 }
2831
2832 // We need to have arguments. This shouldn't happen, but it's worth checking.
2833 if arguments.is_empty() {
2834 return None;
2835 }
2836
2837 // We use a mix of the HIR and the Ty types to get information
2838 // as the HIR doesn't have full types for closure arguments.
f035d41b 2839 let return_ty = sig.output().skip_binder();
dc9dc135 2840 let mut return_span = fn_decl.output.span();
74b04a01 2841 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
9c376795 2842 if let hir::TyKind::Ref(lifetime, _) = ty.kind {
487cf647 2843 return_span = lifetime.ident.span;
dc9dc135
XL
2844 }
2845 }
2846
2847 Some(AnnotatedBorrowFnSignature::NamedFunction {
2848 arguments,
2849 return_ty,
2850 return_span,
2851 })
2852 }
2853 ty::Ref(_, _, _) if is_closure => {
2854 // This is case 2 from above but only for closures, return type is anonymous
2855 // reference so we select
2856 // the first argument.
2857 let argument_span = fn_decl.inputs.first()?.span;
2858 let argument_ty = sig.inputs().skip_binder().first()?;
2859
2860 // Closure arguments are wrapped in a tuple, so we need to get the first
2861 // from that.
1b1a35ee 2862 if let ty::Tuple(elems) = argument_ty.kind() {
5e7ed085 2863 let &argument_ty = elems.first()?;
1b1a35ee 2864 if let ty::Ref(_, _, _) = argument_ty.kind() {
dc9dc135
XL
2865 return Some(AnnotatedBorrowFnSignature::Closure {
2866 argument_ty,
2867 argument_span,
2868 });
2869 }
2870 }
2871
2872 None
2873 }
2874 ty::Ref(_, _, _) => {
2875 // This is also case 2 from above but for functions, return type is still an
2876 // anonymous reference so we select the first argument.
2877 let argument_span = fn_decl.inputs.first()?.span;
5099ac24 2878 let argument_ty = *sig.inputs().skip_binder().first()?;
dc9dc135
XL
2879
2880 let return_span = fn_decl.output.span();
f035d41b 2881 let return_ty = sig.output().skip_binder();
dc9dc135
XL
2882
2883 // We expect the first argument to be a reference.
1b1a35ee 2884 match argument_ty.kind() {
dc9dc135
XL
2885 ty::Ref(_, _, _) => {}
2886 _ => return None,
2887 }
2888
2889 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
2890 argument_ty,
2891 argument_span,
2892 return_ty,
2893 return_span,
2894 })
2895 }
2896 _ => {
2897 // This is case 3 from above, return type is not a reference so don't highlight
2898 // anything.
2899 None
2900 }
2901 }
2902 }
2903}
2904
2905#[derive(Debug)]
2906enum AnnotatedBorrowFnSignature<'tcx> {
2907 NamedFunction {
2908 arguments: Vec<(Ty<'tcx>, Span)>,
2909 return_ty: Ty<'tcx>,
2910 return_span: Span,
2911 },
2912 AnonymousFunction {
2913 argument_ty: Ty<'tcx>,
2914 argument_span: Span,
2915 return_ty: Ty<'tcx>,
2916 return_span: Span,
2917 },
2918 Closure {
2919 argument_ty: Ty<'tcx>,
2920 argument_span: Span,
2921 },
2922}
2923
2924impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
2925 /// Annotate the provided diagnostic with information about borrow from the fn signature that
2926 /// helps explain.
5e7ed085 2927 pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
dc9dc135 2928 match self {
5099ac24 2929 &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
dc9dc135 2930 diag.span_label(
5099ac24 2931 argument_span,
dc9dc135
XL
2932 format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
2933 );
2934
2935 cx.get_region_name_for_ty(argument_ty, 0)
2936 }
5099ac24 2937 &AnnotatedBorrowFnSignature::AnonymousFunction {
dc9dc135
XL
2938 argument_ty,
2939 argument_span,
2940 return_ty,
2941 return_span,
2942 } => {
2943 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
5099ac24 2944 diag.span_label(argument_span, format!("has type `{}`", argument_ty_name));
dc9dc135
XL
2945
2946 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
2947 let types_equal = return_ty_name == argument_ty_name;
2948 diag.span_label(
5099ac24 2949 return_span,
dc9dc135
XL
2950 format!(
2951 "{}has type `{}`",
2952 if types_equal { "also " } else { "" },
2953 return_ty_name,
2954 ),
2955 );
2956
2957 diag.note(
2958 "argument and return type have the same lifetime due to lifetime elision rules",
2959 );
2960 diag.note(
2961 "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
2962 lifetime-syntax.html#lifetime-elision>",
2963 );
2964
2965 cx.get_region_name_for_ty(return_ty, 0)
2966 }
dfeec247 2967 AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
dc9dc135 2968 // Region of return type and arguments checked to be the same earlier.
5099ac24 2969 let region_name = cx.get_region_name_for_ty(*return_ty, 0);
dc9dc135
XL
2970 for (_, argument_span) in arguments {
2971 diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
2972 }
2973
dfeec247 2974 diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,));
dc9dc135
XL
2975
2976 diag.help(&format!(
2977 "use data from the highlighted arguments which match the `{}` lifetime of \
2978 the return type",
2979 region_name,
2980 ));
2981
2982 region_name
2983 }
2984 }
2985 }
2986}
064997fb
FG
2987
2988/// Detect whether one of the provided spans is a statement nested within the top-most visited expr
2989struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
2990
2991impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
2992 fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
2993 match s.kind {
2994 hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
2995 self.1 = true;
2996 }
2997 _ => {}
2998 }
2999 }
3000}
3001
3002/// Given a set of spans representing statements initializing the relevant binding, visit all the
3003/// function expressions looking for branching code paths that *do not* initialize the binding.
3004struct ConditionVisitor<'b> {
3005 spans: &'b [Span],
3006 name: &'b str,
3007 errors: Vec<(Span, String)>,
3008}
3009
3010impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
3011 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
3012 match ex.kind {
3013 hir::ExprKind::If(cond, body, None) => {
3014 // `if` expressions with no `else` that initialize the binding might be missing an
3015 // `else` arm.
3016 let mut v = ReferencedStatementsVisitor(self.spans, false);
3017 v.visit_expr(body);
3018 if v.1 {
3019 self.errors.push((
3020 cond.span,
3021 format!(
3022 "if this `if` condition is `false`, {} is not initialized",
3023 self.name,
3024 ),
3025 ));
3026 self.errors.push((
3027 ex.span.shrink_to_hi(),
3028 format!("an `else` arm might be missing here, initializing {}", self.name),
3029 ));
3030 }
3031 }
3032 hir::ExprKind::If(cond, body, Some(other)) => {
3033 // `if` expressions where the binding is only initialized in one of the two arms
3034 // might be missing a binding initialization.
3035 let mut a = ReferencedStatementsVisitor(self.spans, false);
3036 a.visit_expr(body);
3037 let mut b = ReferencedStatementsVisitor(self.spans, false);
3038 b.visit_expr(other);
3039 match (a.1, b.1) {
3040 (true, true) | (false, false) => {}
3041 (true, false) => {
3042 if other.span.is_desugaring(DesugaringKind::WhileLoop) {
3043 self.errors.push((
3044 cond.span,
3045 format!(
3046 "if this condition isn't met and the `while` loop runs 0 \
3047 times, {} is not initialized",
3048 self.name
3049 ),
3050 ));
3051 } else {
3052 self.errors.push((
3053 body.span.shrink_to_hi().until(other.span),
3054 format!(
3055 "if the `if` condition is `false` and this `else` arm is \
3056 executed, {} is not initialized",
3057 self.name
3058 ),
3059 ));
3060 }
3061 }
3062 (false, true) => {
3063 self.errors.push((
3064 cond.span,
3065 format!(
3066 "if this condition is `true`, {} is not initialized",
3067 self.name
3068 ),
3069 ));
3070 }
3071 }
3072 }
3073 hir::ExprKind::Match(e, arms, loop_desugar) => {
3074 // If the binding is initialized in one of the match arms, then the other match
3075 // arms might be missing an initialization.
3076 let results: Vec<bool> = arms
3077 .iter()
3078 .map(|arm| {
3079 let mut v = ReferencedStatementsVisitor(self.spans, false);
3080 v.visit_arm(arm);
3081 v.1
3082 })
3083 .collect();
3084 if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
3085 for (arm, seen) in arms.iter().zip(results) {
3086 if !seen {
3087 if loop_desugar == hir::MatchSource::ForLoopDesugar {
3088 self.errors.push((
3089 e.span,
3090 format!(
3091 "if the `for` loop runs 0 times, {} is not initialized",
3092 self.name
3093 ),
3094 ));
3095 } else if let Some(guard) = &arm.guard {
3096 self.errors.push((
3097 arm.pat.span.to(guard.body().span),
3098 format!(
3099 "if this pattern and condition are matched, {} is not \
3100 initialized",
3101 self.name
3102 ),
3103 ));
3104 } else {
3105 self.errors.push((
3106 arm.pat.span,
3107 format!(
3108 "if this pattern is matched, {} is not initialized",
3109 self.name
3110 ),
3111 ));
3112 }
3113 }
3114 }
3115 }
3116 }
3117 // FIXME: should we also account for binops, particularly `&&` and `||`? `try` should
3118 // also be accounted for. For now it is fine, as if we don't find *any* relevant
3119 // branching code paths, we point at the places where the binding *is* initialized for
3120 // *some* context.
3121 _ => {}
3122 }
3123 walk_expr(self, ex);
3124 }
3125}