|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 |
| -use borrow_check::WriteKind; |
| 11 | +use borrow_check::{WriteKind, StorageDeadOrDrop}; |
| 12 | +use borrow_check::prefixes::IsPrefixOf; |
12 | 13 | use rustc::middle::region::ScopeTree;
|
13 | 14 | use rustc::mir::VarBindingForm;
|
14 | 15 | use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
|
@@ -394,13 +395,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
394 | 395 | err.buffer(&mut self.errors_buffer);
|
395 | 396 | }
|
396 | 397 |
|
| 398 | + /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. |
| 399 | + /// |
| 400 | + /// This means that some data referenced by `borrow` needs to live |
| 401 | + /// past the point where the StorageDeadOrDrop of `place` occurs. |
| 402 | + /// This is usually interpreted as meaning that `place` has too |
| 403 | + /// short a lifetime. (But sometimes it is more useful to report |
| 404 | + /// it as a more direct conflict between the execution of a |
| 405 | + /// `Drop::drop` with an aliasing borrow.) |
397 | 406 | pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
398 | 407 | &mut self,
|
399 | 408 | context: Context,
|
400 | 409 | borrow: &BorrowData<'tcx>,
|
401 | 410 | place_span: (&Place<'tcx>, Span),
|
402 | 411 | kind: Option<WriteKind>,
|
403 | 412 | ) {
|
| 413 | + debug!("report_borrowed_value_does_not_live_long_enough(\ |
| 414 | + {:?}, {:?}, {:?}, {:?}\ |
| 415 | + )", |
| 416 | + context, borrow, place_span, kind |
| 417 | + ); |
| 418 | + |
404 | 419 | let drop_span = place_span.1;
|
405 | 420 | let scope_tree = self.tcx.region_scope_tree(self.mir_def_id);
|
406 | 421 | let root_place = self
|
@@ -432,6 +447,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
432 | 447 |
|
433 | 448 | let borrow_reason = self.find_why_borrow_contains_point(context, borrow);
|
434 | 449 |
|
| 450 | + if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind |
| 451 | + { |
| 452 | + // If a borrow of path `B` conflicts with drop of `D` (and |
| 453 | + // we're not in the uninteresting case where `B` is a |
| 454 | + // prefix of `D`), then report this as a more interesting |
| 455 | + // destructor conflict. |
| 456 | + if !borrow.borrowed_place.is_prefix_of(place_span.0) { |
| 457 | + self.report_borrow_conflicts_with_destructor( |
| 458 | + context, borrow, borrow_reason, place_span, kind); |
| 459 | + return; |
| 460 | + } |
| 461 | + } |
| 462 | + |
435 | 463 | let mut err = match &self.describe_place(&borrow.borrowed_place) {
|
436 | 464 | Some(_) if self.is_place_thread_local(root_place) => {
|
437 | 465 | self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
|
@@ -495,6 +523,69 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
495 | 523 | err
|
496 | 524 | }
|
497 | 525 |
|
| 526 | + pub(super) fn report_borrow_conflicts_with_destructor( |
| 527 | + &mut self, |
| 528 | + context: Context, |
| 529 | + borrow: &BorrowData<'tcx>, |
| 530 | + borrow_reason: BorrowContainsPointReason<'tcx>, |
| 531 | + place_span: (&Place<'tcx>, Span), |
| 532 | + kind: Option<WriteKind>, |
| 533 | + ) { |
| 534 | + debug!( |
| 535 | + "report_borrow_conflicts_with_destructor(\ |
| 536 | + {:?}, {:?}, {:?}, {:?} {:?}\ |
| 537 | + )", |
| 538 | + context, borrow, borrow_reason, place_span, kind, |
| 539 | + ); |
| 540 | + |
| 541 | + let borrow_spans = self.retrieve_borrow_spans(borrow); |
| 542 | + let borrow_span = borrow_spans.var_or_use(); |
| 543 | + |
| 544 | + let mut err = self.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir); |
| 545 | + |
| 546 | + let drop_span = place_span.1; |
| 547 | + |
| 548 | + let (what_was_dropped, dropped_ty) = { |
| 549 | + let place = place_span.0; |
| 550 | + let desc = match self.describe_place(place) { |
| 551 | + Some(name) => format!("`{}`", name.as_str()), |
| 552 | + None => format!("temporary value"), |
| 553 | + }; |
| 554 | + let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); |
| 555 | + (desc, ty) |
| 556 | + }; |
| 557 | + |
| 558 | + let label = match dropped_ty.sty { |
| 559 | + ty::Adt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() => { |
| 560 | + match self.describe_place(&borrow.borrowed_place) { |
| 561 | + Some(borrowed) => |
| 562 | + format!("here, drop of {D} needs exclusive access to `{B}`, \ |
| 563 | + because the type `{T}` implements the `Drop` trait", |
| 564 | + D=what_was_dropped, T=dropped_ty, B=borrowed), |
| 565 | + None => |
| 566 | + format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait", |
| 567 | + D=what_was_dropped, T=dropped_ty), |
| 568 | + } |
| 569 | + } |
| 570 | + _ => format!("drop of {D} occurs here", D=what_was_dropped), |
| 571 | + }; |
| 572 | + err.span_label(drop_span, label); |
| 573 | + |
| 574 | + // Only give this note and suggestion if they could be relevant |
| 575 | + match borrow_reason { |
| 576 | + BorrowContainsPointReason::Liveness {..} |
| 577 | + | BorrowContainsPointReason::DropLiveness {..} => { |
| 578 | + err.note("consider using a `let` binding to create a longer lived value"); |
| 579 | + } |
| 580 | + BorrowContainsPointReason::OutlivesFreeRegion {..} => (), |
| 581 | + } |
| 582 | + |
| 583 | + self.report_why_borrow_contains_point( |
| 584 | + &mut err, borrow_reason, kind.map(|k| (k, place_span.0))); |
| 585 | + |
| 586 | + err.buffer(&mut self.errors_buffer); |
| 587 | + } |
| 588 | + |
498 | 589 | fn report_thread_local_value_does_not_live_long_enough(
|
499 | 590 | &mut self,
|
500 | 591 | drop_span: Span,
|
|
0 commit comments