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

File tree

29 files changed

+564
-77
lines changed

29 files changed

+564
-77
lines changed

src/librustc/ich/impls_mir.rs

Lines changed: 19 additions & 1 deletion
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

Lines changed: 14 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 15 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 4 additions & 2 deletions
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 16 additions & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 4 additions & 2 deletions
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
}

0 commit comments

Comments
 (0)