Skip to content

Commit a072d1b

Browse files
committed
Auto merge of #54509 - matthewjasper:better-drop-access, r=pnkfelix
[NLL] Rework checking for borrows conflicting with drops Previously, we would split the drop access into multiple checks for each field of a struct/tuple/closure and through `Box` dereferences. This changes this to check if the borrow is accessed by the drop in `places_conflict`. We also now handle enums containing `Drop` types. Closes #53569 r? @nikomatsakis cc @pnkfelix
2 parents e5c6575 + cfbd1a9 commit a072d1b

21 files changed

+282
-416
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+83-25
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use borrow_check::{WriteKind, StorageDeadOrDrop};
11+
use borrow_check::WriteKind;
1212
use borrow_check::prefixes::IsPrefixOf;
1313
use borrow_check::nll::explain_borrow::BorrowExplanation;
1414
use rustc::middle::region::ScopeTree;
1515
use rustc::mir::{
1616
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local,
17-
LocalDecl, LocalKind, Location, Operand, Place, ProjectionElem, Rvalue, Statement,
18-
StatementKind, TerminatorKind, VarBindingForm,
17+
LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue,
18+
Statement, StatementKind, TerminatorKind, VarBindingForm,
1919
};
2020
use rustc::hir;
2121
use rustc::hir::def_id::DefId;
@@ -452,13 +452,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
452452
self.access_place_error_reported
453453
.insert((root_place.clone(), borrow_span));
454454

455-
if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind {
455+
if let StorageDeadOrDrop::Destructor(dropped_ty)
456+
= self.classify_drop_access_kind(&borrow.borrowed_place)
457+
{
456458
// If a borrow of path `B` conflicts with drop of `D` (and
457459
// we're not in the uninteresting case where `B` is a
458460
// prefix of `D`), then report this as a more interesting
459461
// destructor conflict.
460462
if !borrow.borrowed_place.is_prefix_of(place_span.0) {
461-
self.report_borrow_conflicts_with_destructor(context, borrow, place_span, kind);
463+
self.report_borrow_conflicts_with_destructor(
464+
context,
465+
borrow,
466+
place_span,
467+
kind,
468+
dropped_ty,
469+
);
462470
return;
463471
}
464472
}
@@ -566,6 +574,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
566574
borrow: &BorrowData<'tcx>,
567575
(place, drop_span): (&Place<'tcx>, Span),
568576
kind: Option<WriteKind>,
577+
dropped_ty: ty::Ty<'tcx>,
569578
) {
570579
debug!(
571580
"report_borrow_conflicts_with_destructor(\
@@ -579,28 +588,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
579588

580589
let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir);
581590

582-
let (what_was_dropped, dropped_ty) = {
583-
let desc = match self.describe_place(place) {
584-
Some(name) => format!("`{}`", name.as_str()),
585-
None => format!("temporary value"),
586-
};
587-
let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
588-
(desc, ty)
591+
let what_was_dropped = match self.describe_place(place) {
592+
Some(name) => format!("`{}`", name.as_str()),
593+
None => format!("temporary value"),
589594
};
590595

591-
let label = match dropped_ty.sty {
592-
ty::Adt(adt, _) if adt.has_dtor(self.infcx.tcx) && !adt.is_box() => {
593-
match self.describe_place(&borrow.borrowed_place) {
594-
Some(borrowed) =>
595-
format!("here, drop of {D} needs exclusive access to `{B}`, \
596-
because the type `{T}` implements the `Drop` trait",
597-
D=what_was_dropped, T=dropped_ty, B=borrowed),
598-
None =>
599-
format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait",
600-
D=what_was_dropped, T=dropped_ty),
601-
}
602-
}
603-
_ => format!("drop of {D} occurs here", D=what_was_dropped),
596+
let label = match self.describe_place(&borrow.borrowed_place) {
597+
Some(borrowed) =>
598+
format!("here, drop of {D} needs exclusive access to `{B}`, \
599+
because the type `{T}` implements the `Drop` trait",
600+
D=what_was_dropped, T=dropped_ty, B=borrowed),
601+
None =>
602+
format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait",
603+
D=what_was_dropped, T=dropped_ty),
604604
};
605605
err.span_label(drop_span, label);
606606

@@ -880,6 +880,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
880880

881881
pub(super) struct IncludingDowncast(bool);
882882

883+
/// Which case a StorageDeadOrDrop is for.
884+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
885+
enum StorageDeadOrDrop<'tcx> {
886+
LocalStorageDead,
887+
BoxedStorageDead,
888+
Destructor(ty::Ty<'tcx>),
889+
}
890+
883891
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
884892
// End-user visible description of `place` if one can be found. If the
885893
// place is a temporary for instance, None will be returned.
@@ -1167,6 +1175,56 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11671175
}
11681176
}
11691177

1178+
fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
1179+
let tcx = self.infcx.tcx;
1180+
match place {
1181+
Place::Local(_)
1182+
| Place::Static(_)
1183+
| Place::Promoted(_) => StorageDeadOrDrop::LocalStorageDead,
1184+
Place::Projection(box PlaceProjection { base, elem }) => {
1185+
let base_access = self.classify_drop_access_kind(base);
1186+
match elem {
1187+
ProjectionElem::Deref => {
1188+
match base_access {
1189+
StorageDeadOrDrop::LocalStorageDead
1190+
| StorageDeadOrDrop::BoxedStorageDead => {
1191+
assert!(base.ty(self.mir, tcx).to_ty(tcx).is_box(),
1192+
"Drop of value behind a reference or raw pointer");
1193+
StorageDeadOrDrop::BoxedStorageDead
1194+
}
1195+
StorageDeadOrDrop::Destructor(_) => {
1196+
base_access
1197+
}
1198+
}
1199+
}
1200+
ProjectionElem::Field(..)
1201+
| ProjectionElem::Downcast(..) => {
1202+
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
1203+
match base_ty.sty {
1204+
ty::Adt(def, _) if def.has_dtor(tcx) => {
1205+
// Report the outermost adt with a destructor
1206+
match base_access {
1207+
StorageDeadOrDrop::Destructor(_) => {
1208+
base_access
1209+
}
1210+
StorageDeadOrDrop::LocalStorageDead
1211+
| StorageDeadOrDrop::BoxedStorageDead => {
1212+
StorageDeadOrDrop::Destructor(base_ty)
1213+
}
1214+
}
1215+
}
1216+
_ => base_access,
1217+
}
1218+
}
1219+
1220+
ProjectionElem::ConstantIndex { .. }
1221+
| ProjectionElem::Subslice { .. }
1222+
| ProjectionElem::Index(_) => base_access,
1223+
}
1224+
}
1225+
}
1226+
}
1227+
11701228
/// Annotate argument and return type of function and closure with (synthesized) lifetime for
11711229
/// borrow of local value that does not live long enough.
11721230
fn annotate_argument_and_return_for_borrow(

0 commit comments

Comments
 (0)