]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / conflict_errors.rs
CommitLineData
f9f354fc 1use either::Either;
5099ac24 2use rustc_const_eval::util::{CallDesugaringKind, CallKind};
dc9dc135 3use rustc_data_structures::fx::FxHashSet;
dc9dc135 4use rustc_errors::{Applicability, DiagnosticBuilder};
dfeec247
XL
5use rustc_hir as hir;
6use rustc_hir::def_id::DefId;
7use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
ba9703b0
XL
8use rustc_middle::mir::{
9 self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
17df50a5 10 FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
6a06907d 11 ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
ba9703b0 12};
136023e0 13use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
c295e0f8 14use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
6a06907d 15use rustc_span::symbol::sym;
94222f64 16use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
136023e0 17use rustc_trait_selection::infer::InferCtxtExt;
dc9dc135 18
a2a8927a 19use crate::borrow_set::TwoPhaseActivation;
c295e0f8 20use crate::borrowck_errors;
dc9dc135 21
a2a8927a 22use crate::diagnostics::find_all_local_uses;
c295e0f8 23use crate::{
6a06907d
XL
24 borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
25 InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
60c5eb7d
XL
26};
27
28use super::{
a2a8927a 29 explain_borrow::{BorrowExplanation, LaterUseKind},
5099ac24 30 IncludingDowncast, RegionName, RegionNameSource, UseSpans,
60c5eb7d
XL
31};
32
dc9dc135
XL
33#[derive(Debug)]
34struct MoveSite {
35 /// Index of the "move out" that we found. The `MoveData` can
36 /// then tell us where the move occurred.
37 moi: MoveOutIndex,
38
39 /// `true` if we traversed a back edge while walking from the point
40 /// of error to the move site.
dfeec247 41 traversed_back_edge: bool,
dc9dc135
XL
42}
43
44/// Which case a StorageDeadOrDrop is for.
45#[derive(Copy, Clone, PartialEq, Eq, Debug)]
46enum StorageDeadOrDrop<'tcx> {
47 LocalStorageDead,
48 BoxedStorageDead,
49 Destructor(Ty<'tcx>),
50}
51
52impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
c295e0f8 53 pub(crate) fn report_use_of_moved_or_uninitialized(
dc9dc135
XL
54 &mut self,
55 location: Location,
56 desired_action: InitializationRequiringAction,
74b04a01 57 (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),
dc9dc135
XL
58 mpi: MovePathIndex,
59 ) {
60 debug!(
61 "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
62 moved_place={:?} used_place={:?} span={:?} mpi={:?}",
63 location, desired_action, moved_place, used_place, span, mpi
64 );
65
dfeec247
XL
66 let use_spans =
67 self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
dc9dc135
XL
68 let span = use_spans.args_or_use();
69
136023e0 70 let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);
1b1a35ee
XL
71 debug!(
72 "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
73 move_site_vec, use_spans
74 );
dfeec247
XL
75 let move_out_indices: Vec<_> =
76 move_site_vec.iter().map(|move_site| move_site.moi).collect();
dc9dc135
XL
77
78 if move_out_indices.is_empty() {
60c5eb7d 79 let root_place = PlaceRef { projection: &[], ..used_place };
dc9dc135 80
e74abb32 81 if !self.uninitialized_error_reported.insert(root_place) {
dc9dc135
XL
82 debug!(
83 "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
84 root_place
85 );
86 return;
87 }
88
dfeec247
XL
89 let item_msg =
90 match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
91 Some(name) => format!("`{}`", name),
92 None => "value".to_owned(),
93 };
416331ca 94 let mut err = self.cannot_act_on_uninitialized_variable(
dc9dc135
XL
95 span,
96 desired_action.as_noun(),
dfeec247
XL
97 &self
98 .describe_place_with_options(moved_place, IncludingDowncast(true))
dc9dc135 99 .unwrap_or_else(|| "_".to_owned()),
dc9dc135 100 );
e1599b0c 101 err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
dc9dc135 102
17df50a5 103 use_spans.var_span_label_path_only(
dc9dc135
XL
104 &mut err,
105 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
106 );
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
XL
112 debug!(
113 "report_use_of_moved_or_uninitialized place: error suppressed \
114 mois={:?}",
115 move_out_indices
116 );
117 return;
118 }
119 }
120
1b1a35ee
XL
121 let is_partial_move = move_site_vec.iter().any(|move_site| {
122 let move_out = self.move_data.moves[(*move_site).moi];
123 let moved_place = &self.move_data.move_paths[move_out.path].place;
124 // `*(_1)` where `_1` is a `Box` is actually a move out.
29967ef6 125 let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref]
1b1a35ee
XL
126 && self.body.local_decls[moved_place.local].ty.is_box();
127
128 !is_box_move
129 && used_place != moved_place.as_ref()
130 && used_place.is_prefix_of(moved_place.as_ref())
131 });
132
133 let partial_str = if is_partial_move { "partial " } else { "" };
134 let partially_str = if is_partial_move { "partially " } else { "" };
dc9dc135 135
416331ca 136 let mut err = self.cannot_act_on_moved_value(
dc9dc135
XL
137 span,
138 desired_action.as_noun(),
1b1a35ee 139 partially_str,
416331ca 140 self.describe_place_with_options(moved_place, IncludingDowncast(true)),
dc9dc135
XL
141 );
142
136023e0
XL
143 let reinit_spans = maybe_reinitialized_locations
144 .iter()
145 .take(3)
146 .map(|loc| {
147 self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)
148 .args_or_use()
149 })
150 .collect::<Vec<Span>>();
151 let reinits = maybe_reinitialized_locations.len();
152 if reinits == 1 {
153 err.span_label(reinit_spans[0], "this reinitialization might get skipped");
154 } else if reinits > 1 {
155 err.span_note(
156 MultiSpan::from_spans(reinit_spans),
157 &if reinits <= 3 {
158 format!("these {} reinitializations might get skipped", reinits)
159 } else {
160 format!(
161 "these 3 reinitializations and {} other{} might get skipped",
162 reinits - 3,
163 if reinits == 4 { "" } else { "s" }
164 )
165 },
166 );
167 }
168
dfeec247 169 self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
dc9dc135
XL
170
171 let mut is_loop_move = false;
5869c6ff 172 let mut in_pattern = false;
1b1a35ee 173
dc9dc135
XL
174 for move_site in &move_site_vec {
175 let move_out = self.move_data.moves[(*move_site).moi];
176 let moved_place = &self.move_data.move_paths[move_out.path].place;
177
416331ca 178 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
dc9dc135
XL
179 let move_span = move_spans.args_or_use();
180
dfeec247 181 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
dc9dc135 182
5869c6ff
XL
183 let loop_message = if location == move_out.source || move_site.traversed_back_edge {
184 ", in previous iteration of loop"
185 } else {
186 ""
187 };
188
f035d41b 189 if location == move_out.source {
dc9dc135 190 is_loop_move = true;
5869c6ff
XL
191 }
192
193 if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
194 let place_name = self
195 .describe_place(moved_place.as_ref())
196 .map(|n| format!("`{}`", n))
197 .unwrap_or_else(|| "value".to_owned());
198 match kind {
5099ac24
FG
199 CallKind::FnCall { fn_trait_id, .. }
200 if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
201 {
5869c6ff
XL
202 err.span_label(
203 fn_call_span,
204 &format!(
205 "{} {}moved due to this call{}",
206 place_name, partially_str, loop_message
207 ),
208 );
209 err.span_note(
210 var_span,
211 "this value implements `FnOnce`, which causes it to be moved when called",
212 );
213 }
5099ac24
FG
214 CallKind::Operator { self_arg, .. } => {
215 let self_arg = self_arg.unwrap();
5869c6ff
XL
216 err.span_label(
217 fn_call_span,
218 &format!(
219 "{} {}moved due to usage in operator{}",
220 place_name, partially_str, loop_message
221 ),
222 );
223 if self.fn_self_span_reported.insert(fn_span) {
224 err.span_note(
c295e0f8
XL
225 // Check whether the source is accessible
226 if self
227 .infcx
228 .tcx
229 .sess
230 .source_map()
231 .span_to_snippet(self_arg.span)
232 .is_ok()
233 {
234 self_arg.span
235 } else {
236 fn_call_span
237 },
5869c6ff
XL
238 "calling this operator moves the left-hand side",
239 );
240 }
241 }
5099ac24
FG
242 CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
243 let self_arg = self_arg.unwrap();
244 if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
f035d41b
XL
245 err.span_label(
246 fn_call_span,
1b1a35ee 247 &format!(
5869c6ff
XL
248 "{} {}moved due to this implicit call to `.into_iter()`{}",
249 place_name, partially_str, loop_message
1b1a35ee 250 ),
f035d41b 251 );
3c0e092e
XL
252 let sess = self.infcx.tcx.sess;
253 let ty = used_place.ty(self.body, self.infcx.tcx).ty;
254 // If we have a `&mut` ref, we need to reborrow.
255 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
256 // If we are in a loop this will be suggested later.
257 if !is_loop_move {
258 err.span_suggestion_verbose(
259 move_span.shrink_to_lo(),
260 &format!(
261 "consider creating a fresh reborrow of {} here",
262 self.describe_place(moved_place.as_ref())
263 .map(|n| format!("`{}`", n))
264 .unwrap_or_else(
265 || "the mutable reference".to_string()
266 ),
267 ),
268 "&mut *".to_string(),
269 Applicability::MachineApplicable,
270 );
271 }
272 } else if let Ok(snippet) =
273 sess.source_map().span_to_snippet(move_span)
274 {
275 err.span_suggestion(
276 move_span,
277 "consider borrowing to avoid moving into the for loop",
278 format!("&{}", snippet),
279 Applicability::MaybeIncorrect,
280 );
281 }
5869c6ff 282 } else {
f035d41b
XL
283 err.span_label(
284 fn_call_span,
1b1a35ee 285 &format!(
5869c6ff
XL
286 "{} {}moved due to this method call{}",
287 place_name, partially_str, loop_message
1b1a35ee 288 ),
f035d41b 289 );
f035d41b 290 }
136023e0 291 if is_option_or_result && maybe_reinitialized_locations.is_empty() {
cdc7bbd5
XL
292 err.span_suggestion_verbose(
293 fn_call_span.shrink_to_lo(),
294 "consider calling `.as_ref()` to borrow the type's contents",
295 "as_ref().".to_string(),
296 Applicability::MachineApplicable,
297 );
298 }
5869c6ff 299 // Avoid pointing to the same function in multiple different
6a06907d
XL
300 // error messages.
301 if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
302 {
5869c6ff 303 err.span_note(
6a06907d
XL
304 self_arg.span,
305 &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
306 );
f035d41b
XL
307 }
308 }
5099ac24
FG
309 // Other desugarings takes &self, which cannot cause a move
310 _ => unreachable!(),
5869c6ff
XL
311 }
312 } else {
313 err.span_label(
314 move_span,
315 format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
316 );
317 // If the move error occurs due to a loop, don't show
318 // another message for the same span
319 if loop_message.is_empty() {
f035d41b
XL
320 move_spans.var_span_label(
321 &mut err,
1b1a35ee
XL
322 format!(
323 "variable {}moved due to use{}",
324 partially_str,
325 move_spans.describe()
326 ),
17df50a5 327 "moved",
f035d41b
XL
328 );
329 }
330 }
5869c6ff 331
136023e0
XL
332 if let (UseSpans::PatUse(span), []) =
333 (move_spans, &maybe_reinitialized_locations[..])
334 {
335 if maybe_reinitialized_locations.is_empty() {
336 err.span_suggestion_verbose(
337 span.shrink_to_lo(),
338 &format!(
339 "borrow this field in the pattern to avoid moving {}",
340 self.describe_place(moved_place.as_ref())
341 .map(|n| format!("`{}`", n))
342 .unwrap_or_else(|| "the value".to_string())
343 ),
344 "ref ".to_string(),
345 Applicability::MachineApplicable,
346 );
347 in_pattern = true;
348 }
dc9dc135 349 }
dc9dc135
XL
350 }
351
17df50a5 352 use_spans.var_span_label_path_only(
dc9dc135
XL
353 &mut err,
354 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
355 );
356
357 if !is_loop_move {
358 err.span_label(
359 span,
360 format!(
1b1a35ee 361 "value {} here after {}move",
dc9dc135 362 desired_action.as_verb_in_past_tense(),
1b1a35ee 363 partial_str
dc9dc135
XL
364 ),
365 );
366 }
367
5869c6ff 368 let ty = used_place.ty(self.body, self.infcx.tcx).ty;
1b1a35ee 369 let needs_note = match ty.kind() {
dc9dc135 370 ty::Closure(id, _) => {
3dfed10e
XL
371 let tables = self.infcx.tcx.typeck(id.expect_local());
372 let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
dc9dc135
XL
373
374 tables.closure_kind_origins().get(hir_id).is_none()
375 }
376 _ => true,
377 };
378
f035d41b
XL
379 let mpi = self.move_data.moves[move_out_indices[0]].path;
380 let place = &self.move_data.move_paths[mpi].place;
381 let ty = place.ty(self.body, self.infcx.tcx).ty;
382
5869c6ff
XL
383 // If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
384 if is_loop_move & !in_pattern {
1b1a35ee 385 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
f035d41b
XL
386 // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
387 err.span_suggestion_verbose(
388 span.shrink_to_lo(),
389 &format!(
390 "consider creating a fresh reborrow of {} here",
391 self.describe_place(moved_place)
392 .map(|n| format!("`{}`", n))
393 .unwrap_or_else(|| "the mutable reference".to_string()),
394 ),
395 "&mut *".to_string(),
396 Applicability::MachineApplicable,
397 );
398 }
399 }
dc9dc135 400
f035d41b 401 if needs_note {
416331ca
XL
402 let opt_name =
403 self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
dc9dc135
XL
404 let note_msg = match opt_name {
405 Some(ref name) => format!("`{}`", name),
406 None => "value".to_owned(),
407 };
1b1a35ee 408 if let ty::Param(param_ty) = ty.kind() {
dc9dc135 409 let tcx = self.infcx.tcx;
29967ef6 410 let generics = tcx.generics_of(self.mir_def_id());
60c5eb7d 411 let param = generics.type_param(&param_ty, tcx);
29967ef6 412 if let Some(generics) = tcx
5099ac24
FG
413 .typeck_root_def_id(self.mir_def_id().to_def_id())
414 .as_local()
415 .and_then(|def_id| tcx.hir().get_generics(def_id))
dfeec247 416 {
60c5eb7d 417 suggest_constraining_type_param(
74b04a01 418 tcx,
60c5eb7d
XL
419 generics,
420 &mut err,
a2a8927a 421 param.name.as_str(),
60c5eb7d 422 "Copy",
74b04a01 423 None,
dc9dc135
XL
424 );
425 }
426 }
e74abb32
XL
427 let span = if let Some(local) = place.as_local() {
428 let decl = &self.body.local_decls[local];
dc9dc135
XL
429 Some(decl.source_info.span)
430 } else {
431 None
432 };
1b1a35ee
XL
433 self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
434 }
435
436 if let UseSpans::FnSelfUse {
5099ac24 437 kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
1b1a35ee
XL
438 ..
439 } = use_spans
440 {
441 err.note(&format!(
442 "{} occurs due to deref coercion to `{}`",
443 desired_action.as_noun(),
444 deref_target_ty
445 ));
446
c295e0f8
XL
447 // Check first whether the source is accessible (issue #87060)
448 if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
449 err.span_note(deref_target, "deref defined here");
450 }
dc9dc135
XL
451 }
452
5099ac24 453 self.buffer_move_error(move_out_indices, (used_place, err));
dc9dc135
XL
454 }
455 }
456
c295e0f8 457 pub(crate) fn report_move_out_while_borrowed(
dc9dc135
XL
458 &mut self,
459 location: Location,
ba9703b0 460 (place, span): (Place<'tcx>, Span),
dc9dc135
XL
461 borrow: &BorrowData<'tcx>,
462 ) {
463 debug!(
464 "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
465 location, place, span, borrow
466 );
ba9703b0
XL
467 let value_msg = self.describe_any_place(place.as_ref());
468 let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
dc9dc135
XL
469
470 let borrow_spans = self.retrieve_borrow_spans(borrow);
471 let borrow_span = borrow_spans.args_or_use();
472
416331ca 473 let move_spans = self.move_spans(place.as_ref(), location);
dc9dc135
XL
474 let span = move_spans.args_or_use();
475
ba9703b0
XL
476 let mut err =
477 self.cannot_move_when_borrowed(span, &self.describe_any_place(place.as_ref()));
dc9dc135
XL
478 err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
479 err.span_label(span, format!("move out of {} occurs here", value_msg));
480
17df50a5 481 borrow_spans.var_span_label_path_only(
dc9dc135 482 &mut err,
dfeec247 483 format!("borrow occurs due to use{}", borrow_spans.describe()),
dc9dc135
XL
484 );
485
17df50a5
XL
486 move_spans.var_span_label(
487 &mut err,
488 format!("move occurs due to use{}", move_spans.describe()),
489 "moved",
490 );
dc9dc135 491
dfeec247
XL
492 self.explain_why_borrow_contains_point(location, borrow, None)
493 .add_explanation_to_diagnostic(
494 self.infcx.tcx,
495 &self.body,
496 &self.local_names,
497 &mut err,
498 "",
499 Some(borrow_span),
136023e0 500 None,
dfeec247 501 );
5099ac24 502 self.buffer_error(err);
dc9dc135
XL
503 }
504
c295e0f8 505 pub(crate) fn report_use_while_mutably_borrowed(
dc9dc135
XL
506 &mut self,
507 location: Location,
ba9703b0 508 (place, _span): (Place<'tcx>, Span),
dc9dc135
XL
509 borrow: &BorrowData<'tcx>,
510 ) -> DiagnosticBuilder<'cx> {
dc9dc135
XL
511 let borrow_spans = self.retrieve_borrow_spans(borrow);
512 let borrow_span = borrow_spans.args_or_use();
513
514 // Conflicting borrows are reported separately, so only check for move
515 // captures.
416331ca 516 let use_spans = self.move_spans(place.as_ref(), location);
dc9dc135
XL
517 let span = use_spans.var_or_use();
518
17df50a5
XL
519 // 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
520 // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
416331ca 521 let mut err = self.cannot_use_when_mutably_borrowed(
dc9dc135 522 span,
ba9703b0 523 &self.describe_any_place(place.as_ref()),
dc9dc135 524 borrow_span,
ba9703b0 525 &self.describe_any_place(borrow.borrowed_place.as_ref()),
dc9dc135
XL
526 );
527
17df50a5
XL
528 borrow_spans.var_span_label(
529 &mut err,
530 {
531 let place = &borrow.borrowed_place;
532 let desc_place = self.describe_any_place(place.as_ref());
533 format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
534 },
535 "mutable",
536 );
dc9dc135
XL
537
538 self.explain_why_borrow_contains_point(location, borrow, None)
60c5eb7d
XL
539 .add_explanation_to_diagnostic(
540 self.infcx.tcx,
541 &self.body,
542 &self.local_names,
543 &mut err,
544 "",
545 None,
136023e0 546 None,
60c5eb7d 547 );
dc9dc135
XL
548 err
549 }
550
c295e0f8 551 pub(crate) fn report_conflicting_borrow(
dc9dc135
XL
552 &mut self,
553 location: Location,
ba9703b0 554 (place, span): (Place<'tcx>, Span),
dc9dc135
XL
555 gen_borrow_kind: BorrowKind,
556 issued_borrow: &BorrowData<'tcx>,
557 ) -> DiagnosticBuilder<'cx> {
558 let issued_spans = self.retrieve_borrow_spans(issued_borrow);
559 let issued_span = issued_spans.args_or_use();
560
561 let borrow_spans = self.borrow_spans(span, location);
562 let span = borrow_spans.args_or_use();
563
564 let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
565 "generator"
566 } else {
567 "closure"
568 };
569
570 let (desc_place, msg_place, msg_borrow, union_type_name) =
ba9703b0 571 self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);
dc9dc135
XL
572
573 let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
dfeec247 574 let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };
dc9dc135
XL
575
576 // FIXME: supply non-"" `opt_via` when appropriate
dc9dc135 577 let first_borrow_desc;
dfeec247 578 let mut err = match (gen_borrow_kind, issued_borrow.kind) {
60c5eb7d 579 (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
dc9dc135 580 first_borrow_desc = "mutable ";
416331ca 581 self.cannot_reborrow_already_borrowed(
dc9dc135
XL
582 span,
583 &desc_place,
584 &msg_place,
60c5eb7d 585 "immutable",
dc9dc135
XL
586 issued_span,
587 "it",
60c5eb7d 588 "mutable",
dc9dc135
XL
589 &msg_borrow,
590 None,
dc9dc135
XL
591 )
592 }
60c5eb7d 593 (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
dc9dc135 594 first_borrow_desc = "immutable ";
416331ca 595 self.cannot_reborrow_already_borrowed(
dc9dc135
XL
596 span,
597 &desc_place,
598 &msg_place,
60c5eb7d 599 "mutable",
dc9dc135
XL
600 issued_span,
601 "it",
60c5eb7d 602 "immutable",
dc9dc135
XL
603 &msg_borrow,
604 None,
dc9dc135
XL
605 )
606 }
607
60c5eb7d 608 (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
dc9dc135 609 first_borrow_desc = "first ";
74b04a01 610 let mut err = self.cannot_mutably_borrow_multiply(
dc9dc135
XL
611 span,
612 &desc_place,
613 &msg_place,
614 issued_span,
615 &msg_borrow,
616 None,
74b04a01
XL
617 );
618 self.suggest_split_at_mut_if_applicable(
619 &mut err,
ba9703b0
XL
620 place,
621 issued_borrow.borrowed_place,
74b04a01
XL
622 );
623 err
dc9dc135
XL
624 }
625
60c5eb7d 626 (BorrowKind::Unique, BorrowKind::Unique) => {
dc9dc135 627 first_borrow_desc = "first ";
dfeec247 628 self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
dc9dc135
XL
629 }
630
ba9703b0 631 (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
dfeec247 632 if let Some(immutable_section_description) =
ba9703b0 633 self.classify_immutable_section(issued_borrow.assigned_place)
dfeec247 634 {
60c5eb7d
XL
635 let mut err = self.cannot_mutate_in_immutable_section(
636 span,
637 issued_span,
638 &desc_place,
639 immutable_section_description,
640 "mutably borrow",
641 );
642 borrow_spans.var_span_label(
643 &mut err,
644 format!(
ba9703b0 645 "borrow occurs due to use of {}{}",
60c5eb7d
XL
646 desc_place,
647 borrow_spans.describe(),
648 ),
17df50a5 649 "immutable",
60c5eb7d 650 );
dc9dc135 651
60c5eb7d
XL
652 return err;
653 } else {
654 first_borrow_desc = "immutable ";
655 self.cannot_reborrow_already_borrowed(
656 span,
657 &desc_place,
658 &msg_place,
659 "mutable",
660 issued_span,
661 "it",
662 "immutable",
663 &msg_borrow,
664 None,
665 )
666 }
dc9dc135
XL
667 }
668
60c5eb7d 669 (BorrowKind::Unique, _) => {
dc9dc135 670 first_borrow_desc = "first ";
416331ca 671 self.cannot_uniquely_borrow_by_one_closure(
dc9dc135
XL
672 span,
673 container_name,
674 &desc_place,
675 "",
676 issued_span,
677 "it",
678 "",
679 None,
dc9dc135 680 )
dfeec247 681 }
dc9dc135 682
60c5eb7d 683 (BorrowKind::Shared, BorrowKind::Unique) => {
dc9dc135 684 first_borrow_desc = "first ";
416331ca 685 self.cannot_reborrow_already_uniquely_borrowed(
dc9dc135
XL
686 span,
687 container_name,
688 &desc_place,
689 "",
60c5eb7d 690 "immutable",
dc9dc135
XL
691 issued_span,
692 "",
693 None,
694 second_borrow_desc,
dc9dc135
XL
695 )
696 }
697
60c5eb7d 698 (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
dc9dc135 699 first_borrow_desc = "first ";
416331ca 700 self.cannot_reborrow_already_uniquely_borrowed(
dc9dc135
XL
701 span,
702 container_name,
703 &desc_place,
704 "",
60c5eb7d 705 "mutable",
dc9dc135
XL
706 issued_span,
707 "",
708 None,
709 second_borrow_desc,
dc9dc135
XL
710 )
711 }
712
ba9703b0
XL
713 (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
714 | (
715 BorrowKind::Shallow,
716 BorrowKind::Mut { .. }
717 | BorrowKind::Unique
718 | BorrowKind::Shared
719 | BorrowKind::Shallow,
720 ) => unreachable!(),
dc9dc135
XL
721 };
722
723 if issued_spans == borrow_spans {
724 borrow_spans.var_span_label(
725 &mut err,
17df50a5
XL
726 format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
727 gen_borrow_kind.describe_mutability(),
dc9dc135
XL
728 );
729 } else {
730 let borrow_place = &issued_borrow.borrowed_place;
ba9703b0 731 let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
dc9dc135
XL
732 issued_spans.var_span_label(
733 &mut err,
734 format!(
ba9703b0 735 "first borrow occurs due to use of {}{}",
dc9dc135
XL
736 borrow_place_desc,
737 issued_spans.describe(),
738 ),
17df50a5 739 issued_borrow.kind.describe_mutability(),
dc9dc135
XL
740 );
741
742 borrow_spans.var_span_label(
743 &mut err,
744 format!(
ba9703b0 745 "second borrow occurs due to use of {}{}",
dc9dc135
XL
746 desc_place,
747 borrow_spans.describe(),
748 ),
17df50a5 749 gen_borrow_kind.describe_mutability(),
dc9dc135
XL
750 );
751 }
752
753 if union_type_name != "" {
754 err.note(&format!(
ba9703b0 755 "{} is a field of the union `{}`, so it overlaps the field {}",
dc9dc135
XL
756 msg_place, union_type_name, msg_borrow,
757 ));
758 }
759
760 explanation.add_explanation_to_diagnostic(
761 self.infcx.tcx,
60c5eb7d
XL
762 &self.body,
763 &self.local_names,
dc9dc135
XL
764 &mut err,
765 first_borrow_desc,
766 None,
136023e0 767 Some((issued_span, span)),
dc9dc135
XL
768 );
769
a2a8927a
XL
770 self.suggest_using_local_if_applicable(
771 &mut err,
772 location,
773 (place, span),
774 gen_borrow_kind,
775 issued_borrow,
776 explanation,
777 );
778
dc9dc135
XL
779 err
780 }
781
a2a8927a
XL
782 #[instrument(level = "debug", skip(self, err))]
783 fn suggest_using_local_if_applicable(
784 &self,
785 err: &mut DiagnosticBuilder<'_>,
786 location: Location,
787 (place, span): (Place<'tcx>, Span),
788 gen_borrow_kind: BorrowKind,
789 issued_borrow: &BorrowData<'tcx>,
790 explanation: BorrowExplanation,
791 ) {
792 let used_in_call =
793 matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
794 if !used_in_call {
795 debug!("not later used in call");
796 return;
797 }
798
799 let outer_call_loc =
800 if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
801 loc
802 } else {
803 issued_borrow.reserve_location
804 };
805 let outer_call_stmt = self.body.stmt_at(outer_call_loc);
806
807 let inner_param_location = location;
808 let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
809 debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
810 return;
811 };
812 let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
813 debug!(
814 "`inner_param_location` {:?} is not for an assignment: {:?}",
815 inner_param_location, inner_param_stmt
816 );
817 return;
818 };
819 let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
820 let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
821 let Either::Right(term) = self.body.stmt_at(loc) else {
822 debug!("{:?} is a statement, so it can't be a call", loc);
823 return None;
824 };
825 let TerminatorKind::Call { args, .. } = &term.kind else {
826 debug!("not a call: {:?}", term);
827 return None;
828 };
829 debug!("checking call args for uses of inner_param: {:?}", args);
830 if args.contains(&Operand::Move(inner_param)) {
831 Some((loc,term))
832 } else {
833 None
834 }
835 }) else {
836 debug!("no uses of inner_param found as a by-move call arg");
837 return;
838 };
839 debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
840
841 let inner_call_span = inner_call_term.source_info.span;
842 let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
843 if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
844 // FIXME: This stops the suggestion in some cases where it should be emitted.
845 // Fix the spans for those cases so it's emitted correctly.
846 debug!(
847 "outer span {:?} does not strictly contain inner span {:?}",
848 outer_call_span, inner_call_span
849 );
850 return;
851 }
852 err.span_help(inner_call_span, "try adding a local storing this argument...");
853 err.span_help(outer_call_span, "...and then using that local as the argument to this call");
854 }
855
74b04a01
XL
856 fn suggest_split_at_mut_if_applicable(
857 &self,
858 err: &mut DiagnosticBuilder<'_>,
ba9703b0
XL
859 place: Place<'tcx>,
860 borrowed_place: Place<'tcx>,
74b04a01 861 ) {
ba9703b0
XL
862 if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
863 (&place.projection[..], &borrowed_place.projection[..])
864 {
865 err.help(
866 "consider using `.split_at_mut(position)` or similar method to obtain \
74b04a01 867 two mutable non-overlapping sub-slices",
ba9703b0 868 );
74b04a01
XL
869 }
870 }
871
dc9dc135
XL
872 /// Returns the description of the root place for a conflicting borrow and the full
873 /// descriptions of the places that caused the conflict.
874 ///
875 /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
876 /// attempted while a shared borrow is live, then this function will return:
877 ///
878 /// ("x", "", "")
879 ///
880 /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
881 /// a shared borrow of another field `x.y`, then this function will return:
882 ///
883 /// ("x", "x.z", "x.y")
884 ///
885 /// In the more complex union case, where the union is a field of a struct, then if a mutable
886 /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
887 /// another field `x.u.y`, then this function will return:
888 ///
889 /// ("x.u", "x.u.z", "x.u.y")
890 ///
891 /// This is used when creating error messages like below:
892 ///
f9f354fc
XL
893 /// ```text
894 /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
895 /// mutable (via `a.u.s.b`) [E0502]
896 /// ```
c295e0f8 897 pub(crate) fn describe_place_for_conflicting_borrow(
dc9dc135 898 &self,
ba9703b0
XL
899 first_borrowed_place: Place<'tcx>,
900 second_borrowed_place: Place<'tcx>,
dc9dc135
XL
901 ) -> (String, String, String, String) {
902 // Define a small closure that we can use to check if the type of a place
903 // is a union.
5869c6ff
XL
904 let union_ty = |place_base| {
905 // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`;
906 // using a type annotation in the closure argument instead leads to a lifetime error.
907 let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
dc9dc135
XL
908 ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
909 };
dc9dc135
XL
910
911 // Start with an empty tuple, so we can use the functions on `Option` to reduce some
912 // code duplication (particularly around returning an empty description in the failure
913 // case).
914 Some(())
915 .filter(|_| {
916 // If we have a conflicting borrow of the same place, then we don't want to add
917 // an extraneous "via x.y" to our diagnostics, so filter out this case.
918 first_borrowed_place != second_borrowed_place
919 })
920 .and_then(|_| {
921 // We're going to want to traverse the first borrowed place to see if we can find
922 // field access to a union. If we find that, then we will keep the place of the
923 // union being accessed and the field that was being accessed so we can check the
94222f64 924 // second borrowed place for the same union and an access to a different field.
5869c6ff 925 for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
dc9dc135 926 match elem {
5869c6ff
XL
927 ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
928 return Some((place_base, field));
dfeec247
XL
929 }
930 _ => {}
dc9dc135
XL
931 }
932 }
933 None
934 })
935 .and_then(|(target_base, target_field)| {
936 // With the place of a union and a field access into it, we traverse the second
94222f64 937 // borrowed place and look for an access to a different field of the same union.
5869c6ff 938 for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
dc9dc135 939 if let ProjectionElem::Field(field, _) = elem {
5869c6ff
XL
940 if let Some(union_ty) = union_ty(place_base) {
941 if field != target_field && place_base == target_base {
dc9dc135 942 return Some((
5869c6ff 943 self.describe_any_place(place_base),
ba9703b0
XL
944 self.describe_any_place(first_borrowed_place.as_ref()),
945 self.describe_any_place(second_borrowed_place.as_ref()),
dc9dc135
XL
946 union_ty.to_string(),
947 ));
948 }
949 }
950 }
dc9dc135
XL
951 }
952 None
953 })
954 .unwrap_or_else(|| {
955 // If we didn't find a field access into a union, or both places match, then
956 // only return the description of the first place.
957 (
ba9703b0 958 self.describe_any_place(first_borrowed_place.as_ref()),
dc9dc135
XL
959 "".to_string(),
960 "".to_string(),
961 "".to_string(),
962 )
963 })
964 }
965
966 /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
967 ///
968 /// This means that some data referenced by `borrow` needs to live
969 /// past the point where the StorageDeadOrDrop of `place` occurs.
970 /// This is usually interpreted as meaning that `place` has too
971 /// short a lifetime. (But sometimes it is more useful to report
972 /// it as a more direct conflict between the execution of a
973 /// `Drop::drop` with an aliasing borrow.)
c295e0f8 974 pub(crate) fn report_borrowed_value_does_not_live_long_enough(
dc9dc135
XL
975 &mut self,
976 location: Location,
977 borrow: &BorrowData<'tcx>,
ba9703b0 978 place_span: (Place<'tcx>, Span),
dc9dc135
XL
979 kind: Option<WriteKind>,
980 ) {
981 debug!(
982 "report_borrowed_value_does_not_live_long_enough(\
983 {:?}, {:?}, {:?}, {:?}\
984 )",
985 location, borrow, place_span, kind
986 );
987
988 let drop_span = place_span.1;
dfeec247
XL
989 let root_place =
990 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
dc9dc135
XL
991
992 let borrow_spans = self.retrieve_borrow_spans(borrow);
17df50a5 993 let borrow_span = borrow_spans.var_or_use_path_span();
dc9dc135 994
e1599b0c 995 assert!(root_place.projection.is_empty());
74b04a01 996 let proper_span = self.body.local_decls[root_place.local].source_info.span;
dc9dc135 997
e74abb32
XL
998 let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
999
dfeec247 1000 if self.access_place_error_reported.contains(&(
74b04a01 1001 Place { local: root_place.local, projection: root_place_projection },
dfeec247
XL
1002 borrow_span,
1003 )) {
dc9dc135
XL
1004 debug!(
1005 "suppressing access_place error when borrow doesn't live long enough for {:?}",
1006 borrow_span
1007 );
1008 return;
1009 }
1010
dfeec247 1011 self.access_place_error_reported.insert((
74b04a01 1012 Place { local: root_place.local, projection: root_place_projection },
dfeec247
XL
1013 borrow_span,
1014 ));
dc9dc135 1015
dfeec247
XL
1016 let borrowed_local = borrow.borrowed_place.local;
1017 if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
1018 let err =
1019 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
5099ac24 1020 self.buffer_error(err);
dfeec247
XL
1021 return;
1022 }
60c5eb7d 1023
dc9dc135 1024 if let StorageDeadOrDrop::Destructor(dropped_ty) =
416331ca 1025 self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
dc9dc135
XL
1026 {
1027 // If a borrow of path `B` conflicts with drop of `D` (and
1028 // we're not in the uninteresting case where `B` is a
1029 // prefix of `D`), then report this as a more interesting
1030 // destructor conflict.
416331ca 1031 if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
dc9dc135
XL
1032 self.report_borrow_conflicts_with_destructor(
1033 location, borrow, place_span, kind, dropped_ty,
1034 );
1035 return;
1036 }
1037 }
1038
416331ca 1039 let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
dc9dc135
XL
1040
1041 let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
1042 let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
1043
e74abb32
XL
1044 debug!(
1045 "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
dfeec247 1046 place_desc, explanation
e74abb32 1047 );
dc9dc135 1048 let err = match (place_desc, explanation) {
dc9dc135
XL
1049 // If the outlives constraint comes from inside the closure,
1050 // for example:
1051 //
1052 // let x = 0;
1053 // let y = &x;
1054 // Box::new(|| y) as Box<Fn() -> &'static i32>
1055 //
1056 // then just use the normal error. The closure isn't escaping
1057 // and `move` will not help here.
1058 (
1059 Some(ref name),
1060 BorrowExplanation::MustBeValidFor {
ba9703b0 1061 category:
a2a8927a 1062 category @ (ConstraintCategory::Return(_)
ba9703b0
XL
1063 | ConstraintCategory::CallArgument
1064 | ConstraintCategory::OpaqueType),
dc9dc135
XL
1065 from_closure: false,
1066 ref region_name,
1067 span,
1068 ..
1069 },
ba9703b0
XL
1070 ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
1071 .report_escaping_closure_capture(
1072 borrow_spans,
1073 borrow_span,
1074 region_name,
1075 category,
e74abb32 1076 span,
ba9703b0
XL
1077 &format!("`{}`", name),
1078 ),
dc9dc135
XL
1079 (
1080 ref name,
1081 BorrowExplanation::MustBeValidFor {
1082 category: ConstraintCategory::Assignment,
1083 from_closure: false,
dfeec247
XL
1084 region_name:
1085 RegionName {
1086 source:
1087 RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
1088 ..
1089 },
dc9dc135
XL
1090 span,
1091 ..
1092 },
1093 ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
1094 (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
1095 location,
1096 &name,
1097 &borrow,
1098 drop_span,
1099 borrow_spans,
1100 explanation,
1101 ),
1102 (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
1103 location,
1104 &borrow,
1105 drop_span,
1106 borrow_spans,
1107 proper_span,
1108 explanation,
1109 ),
1110 };
1111
5099ac24 1112 self.buffer_error(err);
dc9dc135
XL
1113 }
1114
1115 fn report_local_value_does_not_live_long_enough(
1116 &mut self,
1117 location: Location,
1118 name: &str,
1119 borrow: &BorrowData<'tcx>,
1120 drop_span: Span,
1b1a35ee 1121 borrow_spans: UseSpans<'tcx>,
dc9dc135
XL
1122 explanation: BorrowExplanation,
1123 ) -> DiagnosticBuilder<'cx> {
1124 debug!(
1125 "report_local_value_does_not_live_long_enough(\
1126 {:?}, {:?}, {:?}, {:?}, {:?}\
1127 )",
1128 location, name, borrow, drop_span, borrow_spans
1129 );
1130
17df50a5 1131 let borrow_span = borrow_spans.var_or_use_path_span();
dc9dc135
XL
1132 if let BorrowExplanation::MustBeValidFor {
1133 category,
1134 span,
1135 ref opt_place_desc,
1136 from_closure: false,
1137 ..
dfeec247
XL
1138 } = explanation
1139 {
dc9dc135
XL
1140 if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1141 borrow,
1142 borrow_span,
1143 span,
1144 category,
1145 opt_place_desc.as_ref(),
1146 ) {
1147 return diag;
1148 }
1149 }
1150
dfeec247 1151 let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name));
dc9dc135
XL
1152
1153 if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
1154 let region_name = annotation.emit(self, &mut err);
1155
1156 err.span_label(
1157 borrow_span,
1158 format!("`{}` would have to be valid for `{}`...", name, region_name),
1159 );
1160
29967ef6 1161 let fn_hir_id = self.mir_hir_id();
f9f354fc
XL
1162 err.span_label(
1163 drop_span,
1164 format!(
1165 "...but `{}` will be dropped here, when the {} returns",
1166 name,
1167 self.infcx
1168 .tcx
1169 .hir()
1170 .opt_name(fn_hir_id)
1171 .map(|name| format!("function `{}`", name))
1172 .unwrap_or_else(|| {
1b1a35ee
XL
1173 match &self
1174 .infcx
1175 .tcx
29967ef6 1176 .typeck(self.mir_def_id())
1b1a35ee
XL
1177 .node_type(fn_hir_id)
1178 .kind()
f9f354fc
XL
1179 {
1180 ty::Closure(..) => "enclosing closure",
1181 ty::Generator(..) => "enclosing generator",
1182 kind => bug!("expected closure or generator, found {:?}", kind),
1183 }
1184 .to_string()
1185 })
1186 ),
1187 );
dc9dc135 1188
f9f354fc
XL
1189 err.note(
1190 "functions cannot return a borrow to data owned within the function's scope, \
1191 functions can only return borrows to data passed as arguments",
1192 );
1193 err.note(
1194 "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
1195 references-and-borrowing.html#dangling-references>",
1196 );
dc9dc135
XL
1197
1198 if let BorrowExplanation::MustBeValidFor { .. } = explanation {
1199 } else {
1200 explanation.add_explanation_to_diagnostic(
1201 self.infcx.tcx,
60c5eb7d
XL
1202 &self.body,
1203 &self.local_names,
dc9dc135
XL
1204 &mut err,
1205 "",
1206 None,
136023e0 1207 None,
dc9dc135
XL
1208 );
1209 }
1210 } else {
1211 err.span_label(borrow_span, "borrowed value does not live long enough");
dfeec247 1212 err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
dc9dc135 1213
dfeec247 1214 let within = if borrow_spans.for_generator() { " by generator" } else { "" };
dc9dc135 1215
dfeec247 1216 borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
dc9dc135
XL
1217
1218 explanation.add_explanation_to_diagnostic(
dfeec247
XL
1219 self.infcx.tcx,
1220 &self.body,
1221 &self.local_names,
1222 &mut err,
1223 "",
1224 None,
136023e0 1225 None,
dfeec247 1226 );
dc9dc135
XL
1227 }
1228
1229 err
1230 }
1231
1232 fn report_borrow_conflicts_with_destructor(
1233 &mut self,
1234 location: Location,
1235 borrow: &BorrowData<'tcx>,
ba9703b0 1236 (place, drop_span): (Place<'tcx>, Span),
dc9dc135
XL
1237 kind: Option<WriteKind>,
1238 dropped_ty: Ty<'tcx>,
1239 ) {
1240 debug!(
1241 "report_borrow_conflicts_with_destructor(\
1242 {:?}, {:?}, ({:?}, {:?}), {:?}\
1243 )",
1244 location, borrow, place, drop_span, kind,
1245 );
1246
1247 let borrow_spans = self.retrieve_borrow_spans(borrow);
1248 let borrow_span = borrow_spans.var_or_use();
1249
416331ca 1250 let mut err = self.cannot_borrow_across_destructor(borrow_span);
dc9dc135 1251
416331ca 1252 let what_was_dropped = match self.describe_place(place.as_ref()) {
60c5eb7d 1253 Some(name) => format!("`{}`", name),
dc9dc135
XL
1254 None => String::from("temporary value"),
1255 };
1256
416331ca 1257 let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
dc9dc135
XL
1258 Some(borrowed) => format!(
1259 "here, drop of {D} needs exclusive access to `{B}`, \
1260 because the type `{T}` implements the `Drop` trait",
1261 D = what_was_dropped,
1262 T = dropped_ty,
1263 B = borrowed
1264 ),
1265 None => format!(
1266 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
1267 D = what_was_dropped,
1268 T = dropped_ty
1269 ),
1270 };
1271 err.span_label(drop_span, label);
1272
1273 // Only give this note and suggestion if they could be relevant.
1274 let explanation =
1275 self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
1276 match explanation {
1277 BorrowExplanation::UsedLater { .. }
1278 | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1279 err.note("consider using a `let` binding to create a longer lived value");
1280 }
1281 _ => {}
1282 }
1283
60c5eb7d
XL
1284 explanation.add_explanation_to_diagnostic(
1285 self.infcx.tcx,
1286 &self.body,
1287 &self.local_names,
1288 &mut err,
1289 "",
1290 None,
136023e0 1291 None,
60c5eb7d 1292 );
dc9dc135 1293
5099ac24 1294 self.buffer_error(err);
dc9dc135
XL
1295 }
1296
1297 fn report_thread_local_value_does_not_live_long_enough(
1298 &mut self,
1299 drop_span: Span,
1300 borrow_span: Span,
1301 ) -> DiagnosticBuilder<'cx> {
1302 debug!(
1303 "report_thread_local_value_does_not_live_long_enough(\
1304 {:?}, {:?}\
1305 )",
1306 drop_span, borrow_span
1307 );
1308
416331ca 1309 let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
dc9dc135
XL
1310
1311 err.span_label(
1312 borrow_span,
1313 "thread-local variables cannot be borrowed beyond the end of the function",
1314 );
1315 err.span_label(drop_span, "end of enclosing function is here");
1316
1317 err
1318 }
1319
1320 fn report_temporary_value_does_not_live_long_enough(
1321 &mut self,
1322 location: Location,
1323 borrow: &BorrowData<'tcx>,
1324 drop_span: Span,
1b1a35ee 1325 borrow_spans: UseSpans<'tcx>,
dc9dc135
XL
1326 proper_span: Span,
1327 explanation: BorrowExplanation,
1328 ) -> DiagnosticBuilder<'cx> {
1329 debug!(
1330 "report_temporary_value_does_not_live_long_enough(\
1331 {:?}, {:?}, {:?}, {:?}\
1332 )",
1333 location, borrow, drop_span, proper_span
1334 );
1335
dfeec247
XL
1336 if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
1337 explanation
1338 {
dc9dc135
XL
1339 if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1340 borrow,
1341 proper_span,
1342 span,
1343 category,
1344 None,
1345 ) {
1346 return diag;
1347 }
1348 }
1349
416331ca 1350 let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
dfeec247
XL
1351 err.span_label(proper_span, "creates a temporary which is freed while still in use");
1352 err.span_label(drop_span, "temporary value is freed at the end of this statement");
dc9dc135
XL
1353
1354 match explanation {
1355 BorrowExplanation::UsedLater(..)
1356 | BorrowExplanation::UsedLaterInLoop(..)
1357 | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1358 // Only give this note and suggestion if it could be relevant.
1359 err.note("consider using a `let` binding to create a longer lived value");
1360 }
1361 _ => {}
1362 }
60c5eb7d
XL
1363 explanation.add_explanation_to_diagnostic(
1364 self.infcx.tcx,
1365 &self.body,
1366 &self.local_names,
1367 &mut err,
1368 "",
1369 None,
136023e0 1370 None,
60c5eb7d 1371 );
dc9dc135 1372
dfeec247 1373 let within = if borrow_spans.for_generator() { " by generator" } else { "" };
dc9dc135 1374
dfeec247 1375 borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
dc9dc135
XL
1376
1377 err
1378 }
1379
1380 fn try_report_cannot_return_reference_to_local(
1381 &self,
1382 borrow: &BorrowData<'tcx>,
1383 borrow_span: Span,
1384 return_span: Span,
1385 category: ConstraintCategory,
1386 opt_place_desc: Option<&String>,
1387 ) -> Option<DiagnosticBuilder<'cx>> {
dc9dc135 1388 let return_kind = match category {
f035d41b 1389 ConstraintCategory::Return(_) => "return",
dc9dc135
XL
1390 ConstraintCategory::Yield => "yield",
1391 _ => return None,
1392 };
1393
1394 // FIXME use a better heuristic than Spans
dfeec247
XL
1395 let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span {
1396 "reference to"
1397 } else {
1398 "value referencing"
1399 };
dc9dc135
XL
1400
1401 let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
e74abb32
XL
1402 let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
1403 match self.body.local_kind(local) {
dfeec247
XL
1404 LocalKind::ReturnPointer | LocalKind::Temp => {
1405 bug!("temporary or return pointer with a name")
1406 }
e74abb32 1407 LocalKind::Var => "local variable ",
17df50a5
XL
1408 LocalKind::Arg
1409 if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
1410 {
e74abb32
XL
1411 "variable captured by `move` "
1412 }
dfeec247 1413 LocalKind::Arg => "function parameter ",
dc9dc135 1414 }
e74abb32
XL
1415 } else {
1416 "local data "
dc9dc135
XL
1417 };
1418 (
1419 format!("{}`{}`", local_kind, place_desc),
1420 format!("`{}` is borrowed here", place_desc),
1421 )
1422 } else {
dfeec247
XL
1423 let root_place =
1424 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
1425 let local = root_place.local;
74b04a01 1426 match self.body.local_kind(local) {
dfeec247
XL
1427 LocalKind::ReturnPointer | LocalKind::Temp => {
1428 ("temporary value".to_string(), "temporary value created here".to_string())
1429 }
dc9dc135
XL
1430 LocalKind::Arg => (
1431 "function parameter".to_string(),
1432 "function parameter borrowed here".to_string(),
1433 ),
dfeec247
XL
1434 LocalKind::Var => {
1435 ("local binding".to_string(), "local binding introduced here".to_string())
1436 }
dc9dc135
XL
1437 }
1438 };
1439
416331ca 1440 let mut err = self.cannot_return_reference_to_local(
dc9dc135
XL
1441 return_span,
1442 return_kind,
1443 reference_desc,
1444 &place_desc,
dc9dc135
XL
1445 );
1446
1447 if return_span != borrow_span {
1448 err.span_label(borrow_span, note);
6a06907d
XL
1449
1450 let tcx = self.infcx.tcx;
1451 let ty_params = ty::List::empty();
1452
1453 let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
1454 let return_ty = tcx.erase_regions(return_ty);
1455
1456 // to avoid panics
136023e0
XL
1457 if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
1458 if self
1459 .infcx
1460 .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env)
1461 .must_apply_modulo_regions()
1462 {
1463 if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
1464 err.span_suggestion_hidden(
1465 return_span,
1466 "use `.collect()` to allocate the iterator",
1467 format!("{}{}", snippet, ".collect::<Vec<_>>()"),
1468 Applicability::MaybeIncorrect,
1469 );
6a06907d
XL
1470 }
1471 }
1472 }
dc9dc135
XL
1473 }
1474
1475 Some(err)
1476 }
1477
1478 fn report_escaping_closure_capture(
1479 &mut self,
1b1a35ee 1480 use_span: UseSpans<'tcx>,
dc9dc135
XL
1481 var_span: Span,
1482 fr_name: &RegionName,
1483 category: ConstraintCategory,
1484 constraint_span: Span,
1485 captured_var: &str,
1486 ) -> DiagnosticBuilder<'cx> {
1487 let tcx = self.infcx.tcx;
e74abb32 1488 let args_span = use_span.args_or_use();
dc9dc135 1489
94222f64
XL
1490 let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
1491 Ok(string) => {
e1599b0c 1492 if string.starts_with("async ") {
94222f64
XL
1493 let pos = args_span.lo() + BytePos(6);
1494 (args_span.with_lo(pos).with_hi(pos), "move ".to_string())
e1599b0c 1495 } else if string.starts_with("async|") {
94222f64
XL
1496 let pos = args_span.lo() + BytePos(5);
1497 (args_span.with_lo(pos).with_hi(pos), " move".to_string())
e1599b0c 1498 } else {
94222f64
XL
1499 (args_span.shrink_to_lo(), "move ".to_string())
1500 }
dfeec247 1501 }
94222f64 1502 Err(_) => (args_span, "move |<args>| <body>".to_string()),
dc9dc135 1503 };
e74abb32
XL
1504 let kind = match use_span.generator_kind() {
1505 Some(generator_kind) => match generator_kind {
1506 GeneratorKind::Async(async_kind) => match async_kind {
1507 AsyncGeneratorKind::Block => "async block",
1508 AsyncGeneratorKind::Closure => "async closure",
74b04a01 1509 _ => bug!("async block/closure expected, but async function found."),
e74abb32
XL
1510 },
1511 GeneratorKind::Gen => "generator",
dfeec247 1512 },
e74abb32
XL
1513 None => "closure",
1514 };
ba9703b0
XL
1515
1516 let mut err =
1517 self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
94222f64
XL
1518 err.span_suggestion_verbose(
1519 sugg_span,
e74abb32
XL
1520 &format!(
1521 "to force the {} to take ownership of {} (and any \
1522 other referenced variables), use the `move` keyword",
dfeec247 1523 kind, captured_var
e74abb32 1524 ),
dc9dc135
XL
1525 suggestion,
1526 Applicability::MachineApplicable,
1527 );
1528
5869c6ff 1529 match category {
f035d41b 1530 ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
5869c6ff
XL
1531 let msg = format!("{} is returned here", kind);
1532 err.span_note(constraint_span, &msg);
ba9703b0 1533 }
dc9dc135
XL
1534 ConstraintCategory::CallArgument => {
1535 fr_name.highlight_region_name(&mut err);
5869c6ff
XL
1536 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
1537 err.note(
1538 "async blocks are not executed immediately and must either take a \
1539 reference or ownership of outside variables they use",
1540 );
1541 } else {
1542 let msg = format!("function requires argument type to outlive `{}`", fr_name);
1543 err.span_note(constraint_span, &msg);
1544 }
dc9dc135 1545 }
dfeec247
XL
1546 _ => bug!(
1547 "report_escaping_closure_capture called with unexpected constraint \
74b04a01 1548 category: `{:?}`",
dfeec247
XL
1549 category
1550 ),
5869c6ff
XL
1551 }
1552
dc9dc135
XL
1553 err
1554 }
1555
1556 fn report_escaping_data(
1557 &mut self,
1558 borrow_span: Span,
1559 name: &Option<String>,
1560 upvar_span: Span,
1561 upvar_name: &str,
1562 escape_span: Span,
1563 ) -> DiagnosticBuilder<'cx> {
1564 let tcx = self.infcx.tcx;
1565
29967ef6 1566 let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
dc9dc135 1567
dfeec247
XL
1568 let mut err =
1569 borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
dc9dc135
XL
1570
1571 err.span_label(
1572 upvar_span,
74b04a01 1573 format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from),
dc9dc135
XL
1574 );
1575
dfeec247 1576 err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from));
dc9dc135
XL
1577
1578 if let Some(name) = name {
1579 err.span_label(
1580 escape_span,
1581 format!("reference to `{}` escapes the {} body here", name, escapes_from),
1582 );
1583 } else {
1584 err.span_label(
1585 escape_span,
1586 format!("reference escapes the {} body here", escapes_from),
1587 );
1588 }
1589
1590 err
1591 }
1592
136023e0
XL
1593 fn get_moved_indexes(
1594 &mut self,
1595 location: Location,
1596 mpi: MovePathIndex,
1597 ) -> (Vec<MoveSite>, Vec<Location>) {
a2a8927a
XL
1598 fn predecessor_locations<'a>(
1599 body: &'a mir::Body<'_>,
f9f354fc
XL
1600 location: Location,
1601 ) -> impl Iterator<Item = Location> + 'a {
1602 if location.statement_index == 0 {
1603 let predecessors = body.predecessors()[location.block].to_vec();
1604 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
1605 } else {
1606 Either::Right(std::iter::once(Location {
1607 statement_index: location.statement_index - 1,
1608 ..location
1609 }))
1610 }
1611 }
1612
c295e0f8
XL
1613 let mut mpis = vec![mpi];
1614 let move_paths = &self.move_data.move_paths;
1615 mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
1616
dc9dc135 1617 let mut stack = Vec::new();
c295e0f8
XL
1618 let mut back_edge_stack = Vec::new();
1619
1620 predecessor_locations(self.body, location).for_each(|predecessor| {
1621 if location.dominates(predecessor, &self.dominators) {
1622 back_edge_stack.push(predecessor)
1623 } else {
1624 stack.push(predecessor);
1625 }
1626 });
1627
1628 let mut reached_start = false;
1629
1630 /* Check if the mpi is initialized as an argument */
1631 let mut is_argument = false;
1632 for arg in self.body.args_iter() {
1633 let path = self.move_data.rev_lookup.find_local(arg);
1634 if mpis.contains(&path) {
1635 is_argument = true;
1636 }
1637 }
dc9dc135
XL
1638
1639 let mut visited = FxHashSet::default();
136023e0
XL
1640 let mut move_locations = FxHashSet::default();
1641 let mut reinits = vec![];
dc9dc135
XL
1642 let mut result = vec![];
1643
c295e0f8 1644 let mut dfs_iter = |result: &mut Vec<MoveSite>, location: Location, is_back_edge: bool| {
dc9dc135
XL
1645 debug!(
1646 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
1647 location, is_back_edge
1648 );
1649
1650 if !visited.insert(location) {
c295e0f8 1651 return true;
dc9dc135
XL
1652 }
1653
1654 // check for moves
dfeec247
XL
1655 let stmt_kind =
1656 self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
dc9dc135
XL
1657 if let Some(StatementKind::StorageDead(..)) = stmt_kind {
1658 // this analysis only tries to find moves explicitly
1659 // written by the user, so we ignore the move-outs
1660 // created by `StorageDead` and at the beginning
1661 // of a function.
1662 } else {
1663 // If we are found a use of a.b.c which was in error, then we want to look for
1664 // moves not only of a.b.c but also a.b and a.
1665 //
1666 // Note that the moves data already includes "parent" paths, so we don't have to
1667 // worry about the other case: that is, if there is a move of a.b.c, it is already
1668 // marked as a move of a.b and a as well, so we will generate the correct errors
1669 // there.
dc9dc135
XL
1670 for moi in &self.move_data.loc_map[location] {
1671 debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
1b1a35ee
XL
1672 let path = self.move_data.moves[*moi].path;
1673 if mpis.contains(&path) {
1674 debug!(
1675 "report_use_of_moved_or_uninitialized: found {:?}",
1676 move_paths[path].place
1677 );
dfeec247 1678 result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
136023e0 1679 move_locations.insert(location);
dc9dc135
XL
1680
1681 // Strictly speaking, we could continue our DFS here. There may be
1682 // other moves that can reach the point of error. But it is kind of
1683 // confusing to highlight them.
1684 //
1685 // Example:
1686 //
1687 // ```
1688 // let a = vec![];
1689 // let b = a;
1690 // let c = a;
1691 // drop(a); // <-- current point of error
1692 // ```
1693 //
1694 // Because we stop the DFS here, we only highlight `let c = a`,
1695 // and not `let b = a`. We will of course also report an error at
1696 // `let c = a` which highlights `let b = a` as the move.
c295e0f8 1697 return true;
dc9dc135
XL
1698 }
1699 }
1700 }
1701
1702 // check for inits
1703 let mut any_match = false;
c295e0f8
XL
1704 for ii in &self.move_data.init_loc_map[location] {
1705 let init = self.move_data.inits[*ii];
1706 match init.kind {
1707 InitKind::Deep | InitKind::NonPanicPathOnly => {
1708 if mpis.contains(&init.path) {
1709 any_match = true;
1710 }
dc9dc135 1711 }
c295e0f8
XL
1712 InitKind::Shallow => {
1713 if mpi == init.path {
1714 any_match = true;
1715 }
1716 }
1717 }
1718 }
dc9dc135 1719 if any_match {
136023e0 1720 reinits.push(location);
c295e0f8 1721 return true;
dc9dc135 1722 }
c295e0f8
XL
1723 return false;
1724 };
dc9dc135 1725
c295e0f8
XL
1726 while let Some(location) = stack.pop() {
1727 if dfs_iter(&mut result, location, false) {
1728 continue;
1729 }
1730
1731 let mut has_predecessor = false;
1732 predecessor_locations(self.body, location).for_each(|predecessor| {
1733 if location.dominates(predecessor, &self.dominators) {
1734 back_edge_stack.push(predecessor)
1735 } else {
1736 stack.push(predecessor);
1737 }
1738 has_predecessor = true;
1739 });
1740
1741 if !has_predecessor {
1742 reached_start = true;
1743 }
1744 }
1745 if (is_argument || !reached_start) && result.is_empty() {
1746 /* Process back edges (moves in future loop iterations) only if
1747 the move path is definitely initialized upon loop entry,
1748 to avoid spurious "in previous iteration" errors.
1749 During DFS, if there's a path from the error back to the start
1750 of the function with no intervening init or move, then the
1751 move path may be uninitialized at loop entry.
1752 */
1753 while let Some(location) = back_edge_stack.pop() {
1754 if dfs_iter(&mut result, location, true) {
1755 continue;
1756 }
1757
1758 predecessor_locations(self.body, location)
1759 .for_each(|predecessor| back_edge_stack.push(predecessor));
1760 }
dc9dc135
XL
1761 }
1762
136023e0
XL
1763 // Check if we can reach these reinits from a move location.
1764 let reinits_reachable = reinits
1765 .into_iter()
1766 .filter(|reinit| {
1767 let mut visited = FxHashSet::default();
1768 let mut stack = vec![*reinit];
1769 while let Some(location) = stack.pop() {
1770 if !visited.insert(location) {
1771 continue;
1772 }
1773 if move_locations.contains(&location) {
1774 return true;
1775 }
1776 stack.extend(predecessor_locations(self.body, location));
1777 }
1778 false
1779 })
1780 .collect::<Vec<Location>>();
1781 (result, reinits_reachable)
dc9dc135
XL
1782 }
1783
c295e0f8 1784 pub(crate) fn report_illegal_mutation_of_borrowed(
dc9dc135
XL
1785 &mut self,
1786 location: Location,
ba9703b0 1787 (place, span): (Place<'tcx>, Span),
dc9dc135
XL
1788 loan: &BorrowData<'tcx>,
1789 ) {
1790 let loan_spans = self.retrieve_borrow_spans(loan);
1791 let loan_span = loan_spans.args_or_use();
1792
ba9703b0 1793 let descr_place = self.describe_any_place(place.as_ref());
dc9dc135 1794 if loan.kind == BorrowKind::Shallow {
ba9703b0 1795 if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
60c5eb7d
XL
1796 let mut err = self.cannot_mutate_in_immutable_section(
1797 span,
1798 loan_span,
ba9703b0 1799 &descr_place,
60c5eb7d
XL
1800 section,
1801 "assign",
1802 );
1803 loan_spans.var_span_label(
1804 &mut err,
1805 format!("borrow occurs due to use{}", loan_spans.describe()),
17df50a5 1806 loan.kind.describe_mutability(),
60c5eb7d 1807 );
dc9dc135 1808
5099ac24 1809 self.buffer_error(err);
dc9dc135 1810
60c5eb7d
XL
1811 return;
1812 }
dc9dc135
XL
1813 }
1814
ba9703b0 1815 let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
dc9dc135 1816
17df50a5
XL
1817 loan_spans.var_span_label(
1818 &mut err,
1819 format!("borrow occurs due to use{}", loan_spans.describe()),
1820 loan.kind.describe_mutability(),
1821 );
dfeec247
XL
1822
1823 self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
1824 self.infcx.tcx,
1825 &self.body,
1826 &self.local_names,
dc9dc135 1827 &mut err,
dfeec247
XL
1828 "",
1829 None,
136023e0 1830 None,
dc9dc135
XL
1831 );
1832
6a06907d
XL
1833 self.explain_deref_coercion(loan, &mut err);
1834
5099ac24 1835 self.buffer_error(err);
dc9dc135
XL
1836 }
1837
6a06907d
XL
1838 fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
1839 let tcx = self.infcx.tcx;
1840 if let (
1841 Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
1842 Some((method_did, method_substs)),
1843 ) = (
1844 &self.body[loan.reserve_location.block].terminator,
c295e0f8 1845 rustc_const_eval::util::find_self_call(
6a06907d
XL
1846 tcx,
1847 self.body,
1848 loan.assigned_place.local,
1849 loan.reserve_location.block,
1850 ),
1851 ) {
1852 if tcx.is_diagnostic_item(sym::deref_method, method_did) {
1853 let deref_target =
1854 tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
1855 Instance::resolve(tcx, self.param_env, deref_target, method_substs)
1856 .transpose()
1857 });
1858 if let Some(Ok(instance)) = deref_target {
1859 let deref_target_ty = instance.ty(tcx, self.param_env);
1860 err.note(&format!(
1861 "borrow occurs due to deref coercion to `{}`",
1862 deref_target_ty
1863 ));
1864 err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
1865 }
1866 }
1867 }
1868 }
1869
dc9dc135
XL
1870 /// Reports an illegal reassignment; for example, an assignment to
1871 /// (part of) a non-`mut` local that occurs potentially after that
1872 /// local has already been initialized. `place` is the path being
1873 /// assigned; `err_place` is a place providing a reason why
1874 /// `place` is not mutable (e.g., the non-`mut` local `x` in an
1875 /// assignment to `x.f`).
c295e0f8 1876 pub(crate) fn report_illegal_reassignment(
dc9dc135
XL
1877 &mut self,
1878 _location: Location,
ba9703b0 1879 (place, span): (Place<'tcx>, Span),
dc9dc135 1880 assigned_span: Span,
ba9703b0 1881 err_place: Place<'tcx>,
dc9dc135 1882 ) {
60c5eb7d
XL
1883 let (from_arg, local_decl, local_name) = match err_place.as_local() {
1884 Some(local) => (
1885 self.body.local_kind(local) == LocalKind::Arg,
1886 Some(&self.body.local_decls[local]),
1887 self.local_names[local],
1888 ),
1889 None => (false, None, None),
dc9dc135
XL
1890 };
1891
1892 // If root local is initialized immediately (everything apart from let
1893 // PATTERN;) then make the error refer to that local, rather than the
1894 // place being assigned later.
1895 let (place_description, assigned_span) = match local_decl {
ba9703b0 1896 Some(LocalDecl {
dfeec247 1897 local_info:
f9f354fc 1898 Some(box LocalInfo::User(
ba9703b0
XL
1899 ClearCrossCrate::Clear
1900 | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1901 opt_match_place: None,
1902 ..
1903 })),
f9f354fc
XL
1904 ))
1905 | Some(box LocalInfo::StaticRef { .. })
1906 | None,
dc9dc135
XL
1907 ..
1908 })
ba9703b0
XL
1909 | None => (self.describe_any_place(place.as_ref()), assigned_span),
1910 Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span),
dc9dc135
XL
1911 };
1912
ba9703b0 1913 let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg);
dc9dc135
XL
1914 let msg = if from_arg {
1915 "cannot assign to immutable argument"
1916 } else {
1917 "cannot assign twice to immutable variable"
1918 };
1919 if span != assigned_span {
1920 if !from_arg {
ba9703b0 1921 err.span_label(assigned_span, format!("first assignment to {}", place_description));
dc9dc135
XL
1922 }
1923 }
1924 if let Some(decl) = local_decl {
60c5eb7d 1925 if let Some(name) = local_name {
dc9dc135
XL
1926 if decl.can_be_made_mutable() {
1927 err.span_suggestion(
1928 decl.source_info.span,
cdc7bbd5 1929 "consider making this binding mutable",
dc9dc135
XL
1930 format!("mut {}", name),
1931 Applicability::MachineApplicable,
1932 );
1933 }
1934 }
1935 }
1936 err.span_label(span, msg);
5099ac24 1937 self.buffer_error(err);
dc9dc135
XL
1938 }
1939
74b04a01 1940 fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
dc9dc135 1941 let tcx = self.infcx.tcx;
5869c6ff
XL
1942 match place.last_projection() {
1943 None => StorageDeadOrDrop::LocalStorageDead,
1944 Some((place_base, elem)) => {
e1599b0c 1945 // FIXME(spastorino) make this iterate
5869c6ff 1946 let base_access = self.classify_drop_access_kind(place_base);
dc9dc135
XL
1947 match elem {
1948 ProjectionElem::Deref => match base_access {
1949 StorageDeadOrDrop::LocalStorageDead
1950 | StorageDeadOrDrop::BoxedStorageDead => {
1951 assert!(
5869c6ff 1952 place_base.ty(self.body, tcx).ty.is_box(),
dc9dc135
XL
1953 "Drop of value behind a reference or raw pointer"
1954 );
1955 StorageDeadOrDrop::BoxedStorageDead
1956 }
1957 StorageDeadOrDrop::Destructor(_) => base_access,
1958 },
1959 ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
5869c6ff 1960 let base_ty = place_base.ty(self.body, tcx).ty;
1b1a35ee 1961 match base_ty.kind() {
dc9dc135
XL
1962 ty::Adt(def, _) if def.has_dtor(tcx) => {
1963 // Report the outermost adt with a destructor
1964 match base_access {
1965 StorageDeadOrDrop::Destructor(_) => base_access,
1966 StorageDeadOrDrop::LocalStorageDead
1967 | StorageDeadOrDrop::BoxedStorageDead => {
1968 StorageDeadOrDrop::Destructor(base_ty)
1969 }
1970 }
1971 }
1972 _ => base_access,
1973 }
1974 }
dc9dc135
XL
1975 ProjectionElem::ConstantIndex { .. }
1976 | ProjectionElem::Subslice { .. }
1977 | ProjectionElem::Index(_) => base_access,
1978 }
1979 }
1980 }
1981 }
1982
60c5eb7d 1983 /// Describe the reason for the fake borrow that was assigned to `place`.
ba9703b0
XL
1984 fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> {
1985 use rustc_middle::mir::visit::Visitor;
1986 struct FakeReadCauseFinder<'tcx> {
1987 place: Place<'tcx>,
60c5eb7d
XL
1988 cause: Option<FakeReadCause>,
1989 }
ba9703b0 1990 impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
60c5eb7d
XL
1991 fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
1992 match statement {
cdc7bbd5 1993 Statement { kind: StatementKind::FakeRead(box (cause, place)), .. }
ba9703b0 1994 if *place == self.place =>
dfeec247 1995 {
60c5eb7d
XL
1996 self.cause = Some(*cause);
1997 }
1998 _ => (),
1999 }
2000 }
2001 }
2002 let mut visitor = FakeReadCauseFinder { place, cause: None };
ba9703b0 2003 visitor.visit_body(&self.body);
60c5eb7d
XL
2004 match visitor.cause {
2005 Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
2006 Some(FakeReadCause::ForIndex) => Some("indexing expression"),
2007 _ => None,
2008 }
2009 }
2010
dc9dc135
XL
2011 /// Annotate argument and return type of function and closure with (synthesized) lifetime for
2012 /// borrow of local value that does not live long enough.
2013 fn annotate_argument_and_return_for_borrow(
2014 &self,
2015 borrow: &BorrowData<'tcx>,
2016 ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2017 // Define a fallback for when we can't match a closure.
2018 let fallback = || {
29967ef6 2019 let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
dc9dc135
XL
2020 if is_closure {
2021 None
2022 } else {
29967ef6 2023 let ty = self.infcx.tcx.type_of(self.mir_def_id());
1b1a35ee 2024 match ty.kind() {
f9f354fc 2025 ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
29967ef6
XL
2026 self.mir_def_id().to_def_id(),
2027 self.infcx.tcx.fn_sig(self.mir_def_id()),
f9f354fc 2028 ),
dc9dc135
XL
2029 _ => None,
2030 }
2031 }
2032 };
2033
2034 // In order to determine whether we need to annotate, we need to check whether the reserve
2035 // place was an assignment into a temporary.
2036 //
2037 // If it was, we check whether or not that temporary is eventually assigned into the return
2038 // place. If it was, we can add annotations about the function's return type and arguments
2039 // and it'll make sense.
2040 let location = borrow.reserve_location;
dfeec247
XL
2041 debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
2042 if let Some(&Statement { kind: StatementKind::Assign(box (ref reservation, _)), .. }) =
2043 &self.body[location.block].statements.get(location.statement_index)
dc9dc135 2044 {
dfeec247 2045 debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
dc9dc135 2046 // Check that the initial assignment of the reserve location is into a temporary.
e74abb32
XL
2047 let mut target = match reservation.as_local() {
2048 Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
dc9dc135
XL
2049 _ => return None,
2050 };
2051
2052 // Next, look through the rest of the block, checking if we are assigning the
2053 // `target` (that is, the place that contains our borrow) to anything.
2054 let mut annotated_closure = None;
dfeec247 2055 for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
dc9dc135
XL
2056 debug!(
2057 "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
2058 target, stmt
2059 );
dfeec247 2060 if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
e74abb32
XL
2061 if let Some(assigned_to) = place.as_local() {
2062 debug!(
2063 "annotate_argument_and_return_for_borrow: assigned_to={:?} \
2064 rvalue={:?}",
2065 assigned_to, rvalue
2066 );
2067 // Check if our `target` was captured by a closure.
2068 if let Rvalue::Aggregate(
2069 box AggregateKind::Closure(def_id, substs),
2070 operands,
2071 ) = rvalue
2072 {
2073 for operand in operands {
2074 let assigned_from = match operand {
2075 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2076 assigned_from
2077 }
2078 _ => continue,
2079 };
2080 debug!(
2081 "annotate_argument_and_return_for_borrow: assigned_from={:?}",
dc9dc135 2082 assigned_from
e74abb32 2083 );
dc9dc135 2084
e74abb32
XL
2085 // Find the local from the operand.
2086 let assigned_from_local = match assigned_from.local_or_deref_local()
2087 {
2088 Some(local) => local,
2089 None => continue,
2090 };
dc9dc135 2091
e74abb32
XL
2092 if assigned_from_local != target {
2093 continue;
2094 }
dc9dc135 2095
e74abb32
XL
2096 // If a closure captured our `target` and then assigned
2097 // into a place then we should annotate the closure in
2098 // case it ends up being assigned into the return place.
ba9703b0
XL
2099 annotated_closure =
2100 self.annotate_fn_sig(*def_id, substs.as_closure().sig());
e74abb32
XL
2101 debug!(
2102 "annotate_argument_and_return_for_borrow: \
2103 annotated_closure={:?} assigned_from_local={:?} \
2104 assigned_to={:?}",
2105 annotated_closure, assigned_from_local, assigned_to
2106 );
2107
2108 if assigned_to == mir::RETURN_PLACE {
2109 // If it was assigned directly into the return place, then
2110 // return now.
2111 return annotated_closure;
2112 } else {
2113 // Otherwise, update the target.
2114 target = assigned_to;
2115 }
dc9dc135 2116 }
dc9dc135 2117
e74abb32
XL
2118 // If none of our closure's operands matched, then skip to the next
2119 // statement.
2120 continue;
2121 }
dc9dc135 2122
e74abb32
XL
2123 // Otherwise, look at other types of assignment.
2124 let assigned_from = match rvalue {
2125 Rvalue::Ref(_, _, assigned_from) => assigned_from,
2126 Rvalue::Use(operand) => match operand {
2127 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2128 assigned_from
2129 }
2130 _ => continue,
2131 },
dc9dc135 2132 _ => continue,
e74abb32
XL
2133 };
2134 debug!(
2135 "annotate_argument_and_return_for_borrow: \
2136 assigned_from={:?}",
2137 assigned_from,
2138 );
dc9dc135 2139
e74abb32
XL
2140 // Find the local from the rvalue.
2141 let assigned_from_local = match assigned_from.local_or_deref_local() {
2142 Some(local) => local,
2143 None => continue,
2144 };
2145 debug!(
2146 "annotate_argument_and_return_for_borrow: \
2147 assigned_from_local={:?}",
2148 assigned_from_local,
2149 );
dc9dc135 2150
e74abb32
XL
2151 // Check if our local matches the target - if so, we've assigned our
2152 // borrow to a new place.
2153 if assigned_from_local != target {
2154 continue;
2155 }
dc9dc135 2156
e74abb32
XL
2157 // If we assigned our `target` into a new place, then we should
2158 // check if it was the return place.
2159 debug!(
2160 "annotate_argument_and_return_for_borrow: \
2161 assigned_from_local={:?} assigned_to={:?}",
2162 assigned_from_local, assigned_to
2163 );
2164 if assigned_to == mir::RETURN_PLACE {
2165 // If it was then return the annotated closure if there was one,
2166 // else, annotate this function.
2167 return annotated_closure.or_else(fallback);
2168 }
dc9dc135 2169
e74abb32
XL
2170 // If we didn't assign into the return place, then we just update
2171 // the target.
2172 target = assigned_to;
2173 }
dc9dc135
XL
2174 }
2175 }
2176
2177 // Check the terminator if we didn't find anything in the statements.
2178 let terminator = &self.body[location.block].terminator();
2179 debug!(
2180 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
2181 target, terminator
2182 );
dfeec247
XL
2183 if let TerminatorKind::Call { destination: Some((place, _)), args, .. } =
2184 &terminator.kind
dc9dc135 2185 {
e74abb32 2186 if let Some(assigned_to) = place.as_local() {
dc9dc135 2187 debug!(
e74abb32
XL
2188 "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
2189 assigned_to, args
dc9dc135 2190 );
e74abb32
XL
2191 for operand in args {
2192 let assigned_from = match operand {
2193 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2194 assigned_from
2195 }
2196 _ => continue,
2197 };
dc9dc135 2198 debug!(
e74abb32
XL
2199 "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2200 assigned_from,
dc9dc135
XL
2201 );
2202
e74abb32
XL
2203 if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
2204 debug!(
2205 "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
2206 assigned_from_local,
2207 );
2208
2209 if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
2210 return annotated_closure.or_else(fallback);
2211 }
dc9dc135
XL
2212 }
2213 }
2214 }
2215 }
2216 }
2217
2218 // If we haven't found an assignment into the return place, then we need not add
2219 // any annotations.
2220 debug!("annotate_argument_and_return_for_borrow: none found");
2221 None
2222 }
2223
2224 /// Annotate the first argument and return type of a function signature if they are
2225 /// references.
2226 fn annotate_fn_sig(
2227 &self,
2228 did: DefId,
2229 sig: ty::PolyFnSig<'tcx>,
2230 ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2231 debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
2232 let is_closure = self.infcx.tcx.is_closure(did);
3dfed10e 2233 let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did.as_local()?);
dc9dc135
XL
2234 let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
2235
2236 // We need to work out which arguments to highlight. We do this by looking
2237 // at the return type, where there are three cases:
2238 //
2239 // 1. If there are named arguments, then we should highlight the return type and
2240 // highlight any of the arguments that are also references with that lifetime.
2241 // If there are no arguments that have the same lifetime as the return type,
2242 // then don't highlight anything.
2243 // 2. The return type is a reference with an anonymous lifetime. If this is
2244 // the case, then we can take advantage of (and teach) the lifetime elision
2245 // rules.
2246 //
2247 // We know that an error is being reported. So the arguments and return type
2248 // must satisfy the elision rules. Therefore, if there is a single argument
2249 // then that means the return type and first (and only) argument have the same
2250 // lifetime and the borrow isn't meeting that, we can highlight the argument
2251 // and return type.
2252 //
2253 // If there are multiple arguments then the first argument must be self (else
2254 // it would not satisfy the elision rules), so we can highlight self and the
2255 // return type.
2256 // 3. The return type is not a reference. In this case, we don't highlight
2257 // anything.
2258 let return_ty = sig.output();
1b1a35ee 2259 match return_ty.skip_binder().kind() {
dc9dc135
XL
2260 ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
2261 // This is case 1 from above, return type is a named reference so we need to
2262 // search for relevant arguments.
2263 let mut arguments = Vec::new();
2264 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
1b1a35ee 2265 if let ty::Ref(argument_region, _, _) = argument.kind() {
dc9dc135 2266 if argument_region == return_region {
ba9703b0 2267 // Need to use the `rustc_middle::ty` types to compare against the
dfeec247 2268 // `return_region`. Then use the `rustc_hir` type to get only
dc9dc135 2269 // the lifetime span.
e74abb32 2270 if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
dc9dc135
XL
2271 // With access to the lifetime, we can get
2272 // the span of it.
2273 arguments.push((*argument, lifetime.span));
2274 } else {
2275 bug!("ty type is a ref but hir type is not");
2276 }
2277 }
2278 }
2279 }
2280
2281 // We need to have arguments. This shouldn't happen, but it's worth checking.
2282 if arguments.is_empty() {
2283 return None;
2284 }
2285
2286 // We use a mix of the HIR and the Ty types to get information
2287 // as the HIR doesn't have full types for closure arguments.
f035d41b 2288 let return_ty = sig.output().skip_binder();
dc9dc135 2289 let mut return_span = fn_decl.output.span();
74b04a01 2290 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
e74abb32 2291 if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
dc9dc135
XL
2292 return_span = lifetime.span;
2293 }
2294 }
2295
2296 Some(AnnotatedBorrowFnSignature::NamedFunction {
2297 arguments,
2298 return_ty,
2299 return_span,
2300 })
2301 }
2302 ty::Ref(_, _, _) if is_closure => {
2303 // This is case 2 from above but only for closures, return type is anonymous
2304 // reference so we select
2305 // the first argument.
2306 let argument_span = fn_decl.inputs.first()?.span;
2307 let argument_ty = sig.inputs().skip_binder().first()?;
2308
2309 // Closure arguments are wrapped in a tuple, so we need to get the first
2310 // from that.
1b1a35ee 2311 if let ty::Tuple(elems) = argument_ty.kind() {
dc9dc135 2312 let argument_ty = elems.first()?.expect_ty();
1b1a35ee 2313 if let ty::Ref(_, _, _) = argument_ty.kind() {
dc9dc135
XL
2314 return Some(AnnotatedBorrowFnSignature::Closure {
2315 argument_ty,
2316 argument_span,
2317 });
2318 }
2319 }
2320
2321 None
2322 }
2323 ty::Ref(_, _, _) => {
2324 // This is also case 2 from above but for functions, return type is still an
2325 // anonymous reference so we select the first argument.
2326 let argument_span = fn_decl.inputs.first()?.span;
5099ac24 2327 let argument_ty = *sig.inputs().skip_binder().first()?;
dc9dc135
XL
2328
2329 let return_span = fn_decl.output.span();
f035d41b 2330 let return_ty = sig.output().skip_binder();
dc9dc135
XL
2331
2332 // We expect the first argument to be a reference.
1b1a35ee 2333 match argument_ty.kind() {
dc9dc135
XL
2334 ty::Ref(_, _, _) => {}
2335 _ => return None,
2336 }
2337
2338 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
2339 argument_ty,
2340 argument_span,
2341 return_ty,
2342 return_span,
2343 })
2344 }
2345 _ => {
2346 // This is case 3 from above, return type is not a reference so don't highlight
2347 // anything.
2348 None
2349 }
2350 }
2351 }
2352}
2353
2354#[derive(Debug)]
2355enum AnnotatedBorrowFnSignature<'tcx> {
2356 NamedFunction {
2357 arguments: Vec<(Ty<'tcx>, Span)>,
2358 return_ty: Ty<'tcx>,
2359 return_span: Span,
2360 },
2361 AnonymousFunction {
2362 argument_ty: Ty<'tcx>,
2363 argument_span: Span,
2364 return_ty: Ty<'tcx>,
2365 return_span: Span,
2366 },
2367 Closure {
2368 argument_ty: Ty<'tcx>,
2369 argument_span: Span,
2370 },
2371}
2372
2373impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
2374 /// Annotate the provided diagnostic with information about borrow from the fn signature that
2375 /// helps explain.
c295e0f8 2376 pub(crate) fn emit(
dc9dc135
XL
2377 &self,
2378 cx: &mut MirBorrowckCtxt<'_, 'tcx>,
2379 diag: &mut DiagnosticBuilder<'_>,
2380 ) -> String {
2381 match self {
5099ac24 2382 &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
dc9dc135 2383 diag.span_label(
5099ac24 2384 argument_span,
dc9dc135
XL
2385 format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
2386 );
2387
2388 cx.get_region_name_for_ty(argument_ty, 0)
2389 }
5099ac24 2390 &AnnotatedBorrowFnSignature::AnonymousFunction {
dc9dc135
XL
2391 argument_ty,
2392 argument_span,
2393 return_ty,
2394 return_span,
2395 } => {
2396 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
5099ac24 2397 diag.span_label(argument_span, format!("has type `{}`", argument_ty_name));
dc9dc135
XL
2398
2399 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
2400 let types_equal = return_ty_name == argument_ty_name;
2401 diag.span_label(
5099ac24 2402 return_span,
dc9dc135
XL
2403 format!(
2404 "{}has type `{}`",
2405 if types_equal { "also " } else { "" },
2406 return_ty_name,
2407 ),
2408 );
2409
2410 diag.note(
2411 "argument and return type have the same lifetime due to lifetime elision rules",
2412 );
2413 diag.note(
2414 "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
2415 lifetime-syntax.html#lifetime-elision>",
2416 );
2417
2418 cx.get_region_name_for_ty(return_ty, 0)
2419 }
dfeec247 2420 AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
dc9dc135 2421 // Region of return type and arguments checked to be the same earlier.
5099ac24 2422 let region_name = cx.get_region_name_for_ty(*return_ty, 0);
dc9dc135
XL
2423 for (_, argument_span) in arguments {
2424 diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
2425 }
2426
dfeec247 2427 diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,));
dc9dc135
XL
2428
2429 diag.help(&format!(
2430 "use data from the highlighted arguments which match the `{}` lifetime of \
2431 the return type",
2432 region_name,
2433 ));
2434
2435 region_name
2436 }
2437 }
2438 }
2439}