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