Skip to content

Commit afa8acc

Browse files
committed
Auto merge of #47489 - pnkfelix:limit-2pb-issue-46747, r=nikomatsakis
NLL: Limit two-phase borrows to autoref-introduced borrows This imposes a restriction on two-phase borrows so that it only applies to autoref-introduced borrows. The goal is to ensure that our initial deployment of two-phase borrows is very conservative. We want it to still cover the `v.push(v.len());` example, but we do not want it to cover cases like `let imm = &v; let mu = &mut v; mu.push(imm.len());` (Why do we want it to be conservative? Because when you are not conservative, then the results you get, at least with the current analysis, are tightly coupled to details of the MIR construction that we would rather remain invisible to the end user.) Fix #46747 I decided, for this PR, to add a debug-flag `-Z two-phase-beyond-autoref`, to re-enable the more general approach. But my intention here is *not* that we would eventually turn on that debugflag by default; the main reason I added it was that I thought it was useful for writing tests to be able to write source that looks like desugared MIR.
2 parents 932c736 + b55cd8c commit afa8acc

29 files changed

+564
-77
lines changed

src/librustc/ich/impls_mir.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use std::mem;
2020
impl_stable_hash_for!(struct mir::GeneratorLayout<'tcx> { fields });
2121
impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
2222
impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
23-
impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
2423
impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
2524
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
2625
mutability,
@@ -36,6 +35,25 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator,
3635
impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind });
3736
impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks });
3837

38+
impl<'gcx> HashStable<StableHashingContext<'gcx>>
39+
for mir::BorrowKind {
40+
#[inline]
41+
fn hash_stable<W: StableHasherResult>(&self,
42+
hcx: &mut StableHashingContext<'gcx>,
43+
hasher: &mut StableHasher<W>) {
44+
mem::discriminant(self).hash_stable(hcx, hasher);
45+
46+
match *self {
47+
mir::BorrowKind::Shared |
48+
mir::BorrowKind::Unique => {}
49+
mir::BorrowKind::Mut { allow_two_phase_borrow } => {
50+
allow_two_phase_borrow.hash_stable(hcx, hasher);
51+
}
52+
}
53+
}
54+
}
55+
56+
3957
impl<'gcx> HashStable<StableHashingContext<'gcx>>
4058
for mir::UnsafetyViolationKind {
4159
#[inline]

src/librustc/ich/impls_ty.rs

+14
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,20 @@ impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
163163
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
164164
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
165165

166+
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::adjustment::AutoBorrowMutability {
167+
fn hash_stable<W: StableHasherResult>(&self,
168+
hcx: &mut StableHashingContext<'gcx>,
169+
hasher: &mut StableHasher<W>) {
170+
mem::discriminant(self).hash_stable(hcx, hasher);
171+
match *self {
172+
ty::adjustment::AutoBorrowMutability::Mutable { ref allow_two_phase_borrow } => {
173+
allow_two_phase_borrow.hash_stable(hcx, hasher);
174+
}
175+
ty::adjustment::AutoBorrowMutability::Immutable => {}
176+
}
177+
}
178+
}
179+
166180
impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
167181

168182
impl_stable_hash_for!(enum ty::BorrowKind {

src/librustc/middle/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
760760
expr.span,
761761
cmt_base,
762762
r,
763-
ty::BorrowKind::from_mutbl(m),
763+
ty::BorrowKind::from_mutbl(m.into()),
764764
AutoRef);
765765
}
766766

src/librustc/mir/mod.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,20 @@ pub enum BorrowKind {
413413
Unique,
414414

415415
/// Data is mutable and not aliasable.
416-
Mut,
416+
Mut {
417+
/// True if this borrow arose from method-call auto-ref
418+
/// (i.e. `adjustment::Adjust::Borrow`)
419+
allow_two_phase_borrow: bool
420+
}
421+
}
422+
423+
impl BorrowKind {
424+
pub fn allows_two_phase_borrow(&self) -> bool {
425+
match *self {
426+
BorrowKind::Shared | BorrowKind::Unique => false,
427+
BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow,
428+
}
429+
}
417430
}
418431

419432
///////////////////////////////////////////////////////////////////////////
@@ -1611,7 +1624,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
16111624
Ref(region, borrow_kind, ref place) => {
16121625
let kind_str = match borrow_kind {
16131626
BorrowKind::Shared => "",
1614-
BorrowKind::Mut | BorrowKind::Unique => "mut ",
1627+
BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ",
16151628
};
16161629

16171630
// When printing regions, add trailing space if necessary.

src/librustc/mir/tcx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ impl<'tcx> BinOp {
264264
impl BorrowKind {
265265
pub fn to_mutbl_lossy(self) -> hir::Mutability {
266266
match self {
267-
BorrowKind::Mut => hir::MutMutable,
267+
BorrowKind::Mut { .. } => hir::MutMutable,
268268
BorrowKind::Shared => hir::MutImmutable,
269269

270270
// We have no type corresponding to a unique imm borrow, so

src/librustc/mir/visit.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -951,9 +951,10 @@ impl<'tcx> PlaceContext<'tcx> {
951951
pub fn is_mutating_use(&self) -> bool {
952952
match *self {
953953
PlaceContext::Store | PlaceContext::AsmOutput | PlaceContext::Call |
954-
PlaceContext::Borrow { kind: BorrowKind::Mut, .. } |
954+
PlaceContext::Borrow { kind: BorrowKind::Mut { .. }, .. } |
955955
PlaceContext::Projection(Mutability::Mut) |
956956
PlaceContext::Drop => true,
957+
957958
PlaceContext::Inspect |
958959
PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
959960
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
@@ -971,7 +972,8 @@ impl<'tcx> PlaceContext<'tcx> {
971972
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
972973
PlaceContext::Projection(Mutability::Not) |
973974
PlaceContext::Copy | PlaceContext::Move => true,
974-
PlaceContext::Borrow { kind: BorrowKind::Mut, .. } | PlaceContext::Store |
975+
976+
PlaceContext::Borrow { kind: BorrowKind::Mut { .. }, .. } | PlaceContext::Store |
975977
PlaceContext::AsmOutput |
976978
PlaceContext::Call | PlaceContext::Projection(Mutability::Mut) |
977979
PlaceContext::Drop | PlaceContext::StorageLive | PlaceContext::StorageDead |

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
11211121
"select which borrowck is used (`ast`, `mir`, or `compare`)"),
11221122
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
11231123
"use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
1124+
two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED],
1125+
"when using two-phase-borrows, allow two phases even for non-autoref `&mut` borrows"),
11241126
time_passes: bool = (false, parse_bool, [UNTRACKED],
11251127
"measure time of each rustc pass"),
11261128
count_llvm_insns: bool = (false, parse_bool,

src/librustc/ty/adjustment.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,25 @@ impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
119119
}
120120
}
121121

122+
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
123+
pub enum AutoBorrowMutability {
124+
Mutable { allow_two_phase_borrow: bool },
125+
Immutable,
126+
}
127+
128+
impl From<AutoBorrowMutability> for hir::Mutability {
129+
fn from(m: AutoBorrowMutability) -> Self {
130+
match m {
131+
AutoBorrowMutability::Mutable { .. } => hir::MutMutable,
132+
AutoBorrowMutability::Immutable => hir::MutImmutable,
133+
}
134+
}
135+
}
136+
122137
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
123138
pub enum AutoBorrow<'tcx> {
124139
/// Convert from T to &T.
125-
Ref(ty::Region<'tcx>, hir::Mutability),
140+
Ref(ty::Region<'tcx>, AutoBorrowMutability),
126141

127142
/// Convert from T to *T.
128143
RawPtr(hir::Mutability),

src/librustc_const_eval/pattern.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
134134
BindingMode::ByValue => mutability == Mutability::Mut,
135135
BindingMode::ByRef(_, bk) => {
136136
write!(f, "ref ")?;
137-
bk == BorrowKind::Mut
137+
match bk { BorrowKind::Mut { .. } => true, _ => false }
138138
}
139139
};
140140
if is_mut {
@@ -429,7 +429,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
429429
(Mutability::Not, BindingMode::ByValue),
430430
ty::BindByReference(hir::MutMutable) =>
431431
(Mutability::Not, BindingMode::ByRef(
432-
region.unwrap(), BorrowKind::Mut)),
432+
region.unwrap(), BorrowKind::Mut { allow_two_phase_borrow: false })),
433433
ty::BindByReference(hir::MutImmutable) =>
434434
(Mutability::Not, BindingMode::ByRef(
435435
region.unwrap(), BorrowKind::Shared)),

src/librustc_lint/unused.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
437437
for adj in cx.tables.expr_adjustments(e) {
438438
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
439439
let msg = match m {
440-
hir::MutImmutable => "unnecessary allocation, use & instead",
441-
hir::MutMutable => "unnecessary allocation, use &mut instead"
440+
adjustment::AutoBorrowMutability::Immutable =>
441+
"unnecessary allocation, use & instead",
442+
adjustment::AutoBorrowMutability::Mutable { .. }=>
443+
"unnecessary allocation, use &mut instead"
442444
};
443445
cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
444446
}

src/librustc_mir/borrow_check/error_reporting.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
256256
"immutable",
257257
"mutable",
258258
) {
259-
(BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
260-
(BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
259+
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) |
260+
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
261261
.cannot_reborrow_already_borrowed(
262262
span,
263263
&desc_place,
@@ -271,7 +271,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
271271
Origin::Mir,
272272
),
273273

274-
(BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) => self.tcx
274+
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => self.tcx
275275
.cannot_mutably_borrow_multiply(
276276
span,
277277
&desc_place,
@@ -314,7 +314,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
314314
Origin::Mir,
315315
),
316316

317-
(BorrowKind::Mut, _, lft, BorrowKind::Unique, _, _) => self.tcx
317+
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => self.tcx
318318
.cannot_reborrow_already_uniquely_borrowed(
319319
span,
320320
&desc_place,

src/librustc_mir/borrow_check/mod.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,15 @@ impl InitializationRequiringAction {
707707
}
708708

709709
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
710+
/// Returns true if the borrow represented by `kind` is
711+
/// allowed to be split into separate Reservation and
712+
/// Activation phases.
713+
fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool {
714+
self.tcx.sess.two_phase_borrows() &&
715+
(kind.allows_two_phase_borrow() ||
716+
self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
717+
}
718+
710719
/// Checks an access to the given place to see if it is allowed. Examines the set of borrows
711720
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
712721
/// place is initialized and (b) it is not borrowed in some way that would prevent this
@@ -797,9 +806,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
797806
Control::Continue
798807
}
799808

800-
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut) => {
809+
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
801810
// Reading from mere reservations of mutable-borrows is OK.
802-
if this.tcx.sess.two_phase_borrows() && index.is_reservation()
811+
if this.allow_two_phase_borrow(borrow.kind) && index.is_reservation()
803812
{
804813
return Control::Continue;
805814
}
@@ -828,7 +837,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
828837
}
829838

830839
(Reservation(kind), BorrowKind::Unique)
831-
| (Reservation(kind), BorrowKind::Mut)
840+
| (Reservation(kind), BorrowKind::Mut { .. })
832841
| (Activation(kind, _), _)
833842
| (Write(kind), _) => {
834843
match rw {
@@ -945,9 +954,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
945954
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
946955
let access_kind = match bk {
947956
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
948-
BorrowKind::Unique | BorrowKind::Mut => {
957+
BorrowKind::Unique | BorrowKind::Mut { .. } => {
949958
let wk = WriteKind::MutableBorrow(bk);
950-
if self.tcx.sess.two_phase_borrows() {
959+
if self.allow_two_phase_borrow(bk) {
951960
(Deep, Reservation(wk))
952961
} else {
953962
(Deep, Write(wk))
@@ -1196,7 +1205,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11961205
// mutable borrow before we check it.
11971206
match borrow.kind {
11981207
BorrowKind::Shared => return,
1199-
BorrowKind::Unique | BorrowKind::Mut => {}
1208+
BorrowKind::Unique | BorrowKind::Mut { .. } => {}
12001209
}
12011210

12021211
self.access_place(
@@ -1467,8 +1476,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14671476
span_bug!(span, "&unique borrow for {:?} should not fail", place);
14681477
}
14691478
}
1470-
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut))
1471-
| Write(WriteKind::MutableBorrow(BorrowKind::Mut)) => if let Err(place_err) =
1479+
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { .. }))
1480+
| Write(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) => if let Err(place_err) =
14721481
self.is_mutable(place, is_local_mutation_allowed)
14731482
{
14741483
error_reported = true;
@@ -1532,7 +1541,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15321541
Activation(..) => {} // permission checks are done at Reservation point.
15331542

15341543
Read(ReadKind::Borrow(BorrowKind::Unique))
1535-
| Read(ReadKind::Borrow(BorrowKind::Mut))
1544+
| Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
15361545
| Read(ReadKind::Borrow(BorrowKind::Shared))
15371546
| Read(ReadKind::Copy) => {} // Access authorized
15381547
}

src/librustc_mir/dataflow/impls/borrows.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
122122
let kind = match self.kind {
123123
mir::BorrowKind::Shared => "",
124124
mir::BorrowKind::Unique => "uniq ",
125-
mir::BorrowKind::Mut => "mut ",
125+
mir::BorrowKind::Mut { .. } => "mut ",
126126
};
127127
let region = format!("{}", self.region);
128128
let region = if region.len() > 0 { format!("{} ", region) } else { region };

src/librustc_mir/hair/cx/expr.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ use hair::cx::to_ref::ToRef;
1717
use rustc::hir::def::{Def, CtorKind};
1818
use rustc::middle::const_val::ConstVal;
1919
use rustc::ty::{self, AdtKind, VariantDef, Ty};
20-
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
20+
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
2121
use rustc::ty::cast::CastKind as TyCastKind;
2222
use rustc::hir;
2323
use rustc::hir::def_id::LocalDefId;
24+
use rustc::mir::{BorrowKind};
2425

2526
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
2627
type Output = Expr<'tcx>;
@@ -111,7 +112,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
111112
span,
112113
kind: ExprKind::Borrow {
113114
region: deref.region,
114-
borrow_kind: to_borrow_kind(deref.mutbl),
115+
borrow_kind: deref.mutbl.to_borrow_kind(),
115116
arg: expr.to_ref(),
116117
},
117118
};
@@ -121,7 +122,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
121122
Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
122123
ExprKind::Borrow {
123124
region: r,
124-
borrow_kind: to_borrow_kind(m),
125+
borrow_kind: m.to_borrow_kind(),
125126
arg: expr.to_ref(),
126127
}
127128
}
@@ -141,7 +142,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
141142
span,
142143
kind: ExprKind::Borrow {
143144
region,
144-
borrow_kind: to_borrow_kind(m),
145+
borrow_kind: m.to_borrow_kind(),
145146
arg: expr.to_ref(),
146147
},
147148
};
@@ -287,7 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
287288
};
288289
ExprKind::Borrow {
289290
region,
290-
borrow_kind: to_borrow_kind(mutbl),
291+
borrow_kind: mutbl.to_borrow_kind(),
291292
arg: expr.to_ref(),
292293
}
293294
}
@@ -642,10 +643,25 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
642643
}
643644
}
644645

645-
fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
646-
match m {
647-
hir::MutMutable => BorrowKind::Mut,
648-
hir::MutImmutable => BorrowKind::Shared,
646+
trait ToBorrowKind { fn to_borrow_kind(&self) -> BorrowKind; }
647+
648+
impl ToBorrowKind for AutoBorrowMutability {
649+
fn to_borrow_kind(&self) -> BorrowKind {
650+
match *self {
651+
AutoBorrowMutability::Mutable { allow_two_phase_borrow } =>
652+
BorrowKind::Mut { allow_two_phase_borrow },
653+
AutoBorrowMutability::Immutable =>
654+
BorrowKind::Shared,
655+
}
656+
}
657+
}
658+
659+
impl ToBorrowKind for hir::Mutability {
660+
fn to_borrow_kind(&self) -> BorrowKind {
661+
match *self {
662+
hir::MutMutable => BorrowKind::Mut { allow_two_phase_borrow: false },
663+
hir::MutImmutable => BorrowKind::Shared,
664+
}
649665
}
650666
}
651667

@@ -947,7 +963,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
947963
let borrow_kind = match upvar_borrow.kind {
948964
ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
949965
ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
950-
ty::BorrowKind::MutBorrow => BorrowKind::Mut,
966+
ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }
951967
};
952968
Expr {
953969
temp_lifetime,

0 commit comments

Comments
 (0)