Skip to content

Commit 31eb0e2

Browse files
committed
Auto merge of #57609 - matthewjasper:more-restrictive-match, r=pnkfelix
Use normal mutable borrows in matches `ref mut` borrows are currently two-phase with NLL enabled. This changes them to be proper mutable borrows. To accommodate this, first the position of fake borrows is changed: ```text [ 1. Pre-match ] | [ (old create fake borrows) ] [ 2. Discriminant testing -- check discriminants ] <-+ | | | (once a specific arm is chosen) | | | [ (old read fake borrows) ] | [ 3. Create "guard bindings" for arm ] | [ (create fake borrows) ] | | | [ 4. Execute guard code ] | [ (read fake borrows) ] --(guard is false)-----------+ | | (guard results in true) | [ 5. Create real bindings and execute arm ] | [ Exit match ] ``` The following additional changes are made to accommodate `ref mut` bindings: * We no longer create fake `Shared` borrows. These borrows are no longer needed for soundness, just to avoid some arguably strange cases. * `Shallow` borrows no longer conflict with existing borrows, avoiding conflicting access between the guard borrow access and the `ref mut` borrow. There is some further clean up done in this PR: * Avoid the "later used here" note for Shallow borrows (since it's not relevant with the message provided) * Make any use of a two-phase borrow activate it. * Simplify the cleanup_post_borrowck passes into a single pass. cc #56254 r? @nikomatsakis
2 parents c1911ba + 5ffc919 commit 31eb0e2

27 files changed

+1198
-1178
lines changed

src/librustc/ich/impls_mir.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,12 @@ impl_stable_hash_for!(impl<'gcx> for enum mir::StatementKind<'gcx> [ mir::Statem
196196
});
197197

198198
impl_stable_hash_for!(enum mir::RetagKind { FnEntry, TwoPhase, Raw, Default });
199-
impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet });
199+
impl_stable_hash_for!(enum mir::FakeReadCause {
200+
ForMatchGuard,
201+
ForMatchedPlace,
202+
ForGuardBinding,
203+
ForLet
204+
});
200205

201206
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
202207
fn hash_stable<W: StableHasherResult>(&self,

src/librustc/mir/mod.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1823,17 +1823,22 @@ pub enum RetagKind {
18231823
/// The `FakeReadCause` describes the type of pattern why a `FakeRead` statement exists.
18241824
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
18251825
pub enum FakeReadCause {
1826-
/// Inject a fake read of the borrowed input at the start of each arm's
1827-
/// pattern testing code.
1826+
/// Inject a fake read of the borrowed input at the end of each guards
1827+
/// code.
18281828
///
1829-
/// This should ensure that you cannot change the variant for an enum
1830-
/// while you are in the midst of matching on it.
1829+
/// This should ensure that you cannot change the variant for an enum while
1830+
/// you are in the midst of matching on it.
18311831
ForMatchGuard,
18321832

18331833
/// `let x: !; match x {}` doesn't generate any read of x so we need to
18341834
/// generate a read of x to check that it is initialized and safe.
18351835
ForMatchedPlace,
18361836

1837+
/// A fake read of the RefWithinGuard version of a bind-by-value variable
1838+
/// in a match guard to ensure that it's value hasn't change by the time
1839+
/// we create the OutsideGuard version.
1840+
ForGuardBinding,
1841+
18371842
/// Officially, the semantics of
18381843
///
18391844
/// `let pattern = <expr>;`

src/librustc_mir/borrow_check/borrow_set.rs

+16-28
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use crate::borrow_check::nll::ToRegionVid;
33
use crate::dataflow::indexes::BorrowIndex;
44
use crate::dataflow::move_paths::MoveData;
55
use rustc::mir::traversal;
6-
use rustc::mir::visit::{
7-
PlaceContext, Visitor, NonUseContext, MutatingUseContext, NonMutatingUseContext
8-
};
6+
use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
97
use rustc::mir::{self, Location, Mir, Local};
108
use rustc::ty::{RegionVid, TyCtxt};
119
use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -257,31 +255,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
257255
);
258256
}
259257

260-
// Otherwise, this is the unique later use
261-
// that we expect.
262-
borrow_data.activation_location = match context {
263-
// The use of TMP in a shared borrow does not
264-
// count as an actual activation.
265-
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
266-
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) =>
267-
TwoPhaseActivation::NotActivated,
268-
_ => {
269-
// Double check: This borrow is indeed a two-phase borrow (that is,
270-
// we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
271-
// we've not found any other activations (checked above).
272-
assert_eq!(
273-
borrow_data.activation_location,
274-
TwoPhaseActivation::NotActivated,
275-
"never found an activation for this borrow!",
276-
);
277-
278-
self.activation_map
279-
.entry(location)
280-
.or_default()
281-
.push(borrow_index);
282-
TwoPhaseActivation::ActivatedAt(location)
283-
}
284-
};
258+
// Otherwise, this is the unique later use that we expect.
259+
// Double check: This borrow is indeed a two-phase borrow (that is,
260+
// we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
261+
// we've not found any other activations (checked above).
262+
assert_eq!(
263+
borrow_data.activation_location,
264+
TwoPhaseActivation::NotActivated,
265+
"never found an activation for this borrow!",
266+
);
267+
self.activation_map
268+
.entry(location)
269+
.or_default()
270+
.push(borrow_index);
271+
272+
borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
285273
}
286274
}
287275

src/librustc_mir/borrow_check/error_reporting.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -1336,22 +1336,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13361336
let loan_span = loan_spans.args_or_use();
13371337

13381338
let tcx = self.infcx.tcx;
1339-
let mut err = if loan.kind == BorrowKind::Shallow {
1340-
tcx.cannot_mutate_in_match_guard(
1339+
if loan.kind == BorrowKind::Shallow {
1340+
let mut err = tcx.cannot_mutate_in_match_guard(
13411341
span,
13421342
loan_span,
13431343
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
13441344
"assign",
13451345
Origin::Mir,
1346-
)
1347-
} else {
1348-
tcx.cannot_assign_to_borrowed(
1349-
span,
1350-
loan_span,
1351-
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
1352-
Origin::Mir,
1353-
)
1354-
};
1346+
);
1347+
loan_spans.var_span_label(
1348+
&mut err,
1349+
format!("borrow occurs due to use{}", loan_spans.describe()),
1350+
);
1351+
1352+
err.buffer(&mut self.errors_buffer);
1353+
1354+
return;
1355+
}
1356+
1357+
let mut err = tcx.cannot_assign_to_borrowed(
1358+
span,
1359+
loan_span,
1360+
&self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
1361+
Origin::Mir,
1362+
);
13551363

13561364
loan_spans.var_span_label(
13571365
&mut err,

src/librustc_mir/borrow_check/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
998998
}
999999

10001000
(Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared)
1001-
| (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => {
1001+
| (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow)
1002+
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique)
1003+
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
10021004
Control::Continue
10031005
}
10041006

src/librustc_mir/borrow_check/nll/invalidation.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,8 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
7878
JustWrite
7979
);
8080
}
81-
StatementKind::FakeRead(_, ref place) => {
82-
self.access_place(
83-
ContextKind::FakeRead.new(location),
84-
place,
85-
(Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
86-
LocalMutationIsAllowed::No,
87-
);
81+
StatementKind::FakeRead(_, _) => {
82+
// Only relavent for initialized/liveness/safety checks.
8883
}
8984
StatementKind::SetDiscriminant {
9085
ref place,
@@ -438,7 +433,9 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
438433
}
439434

440435
(Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow)
441-
| (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => {
436+
| (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared)
437+
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique)
438+
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
442439
// Reads/reservations don't invalidate shared or shallow borrows
443440
}
444441

src/librustc_mir/build/block.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ use rustc::mir::*;
66
use rustc::hir;
77
use syntax_pos::Span;
88

9-
use std::slice;
10-
119
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1210
pub fn ast_block(&mut self,
1311
destination: &Place<'tcx>,
@@ -125,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
125123
None,
126124
remainder_span,
127125
lint_level,
128-
slice::from_ref(&pattern),
126+
&pattern,
129127
ArmHasGuard(false),
130128
Some((None, initializer_span)),
131129
);
@@ -138,7 +136,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
138136
}));
139137
} else {
140138
scope = this.declare_bindings(
141-
None, remainder_span, lint_level, slice::from_ref(&pattern),
139+
None, remainder_span, lint_level, &pattern,
142140
ArmHasGuard(false), None);
143141

144142
debug!("ast_block_stmts: pattern={:?}", pattern);

src/librustc_mir/build/expr/into.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5353
ExprKind::Block { body: ast_block } => {
5454
this.ast_block(destination, block, ast_block, source_info)
5555
}
56-
ExprKind::Match { discriminant, arms } => {
57-
this.match_expr(destination, expr_span, block, discriminant, arms)
56+
ExprKind::Match { scrutinee, arms } => {
57+
this.match_expr(destination, expr_span, block, scrutinee, arms)
5858
}
5959
ExprKind::NeverToAny { source } => {
6060
let source = this.hir.mirror(source);

0 commit comments

Comments
 (0)