Skip to content

Commit c8041dd

Browse files
committed
Add AutoBorrowMutability; its like hir::Mutability but w/ two-phase borrow info too.
Namely, the mutable borrows also carries a flag indicating whether they should support two-phase borrows. This allows us to thread down, from the point of the borrow's introduction, whether the particular adjustment that created it is one that yields two-phase mutable borrows.
1 parent 1855ab7 commit c8041dd

File tree

11 files changed

+154
-28
lines changed

11 files changed

+154
-28
lines changed

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/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_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
}

src/librustc_mir/hair/cx/expr.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ 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;
@@ -112,7 +112,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
112112
span,
113113
kind: ExprKind::Borrow {
114114
region: deref.region,
115-
borrow_kind: to_borrow_kind(deref.mutbl, true),
115+
borrow_kind: deref.mutbl.to_borrow_kind(),
116116
arg: expr.to_ref(),
117117
},
118118
};
@@ -122,7 +122,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
122122
Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
123123
ExprKind::Borrow {
124124
region: r,
125-
borrow_kind: to_borrow_kind(m, true),
125+
borrow_kind: m.to_borrow_kind(),
126126
arg: expr.to_ref(),
127127
}
128128
}
@@ -142,7 +142,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
142142
span,
143143
kind: ExprKind::Borrow {
144144
region,
145-
borrow_kind: to_borrow_kind(m, true),
145+
borrow_kind: m.to_borrow_kind(),
146146
arg: expr.to_ref(),
147147
},
148148
};
@@ -288,7 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
288288
};
289289
ExprKind::Borrow {
290290
region,
291-
borrow_kind: to_borrow_kind(mutbl, false),
291+
borrow_kind: mutbl.to_borrow_kind(),
292292
arg: expr.to_ref(),
293293
}
294294
}
@@ -643,10 +643,25 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
643643
}
644644
}
645645

646-
fn to_borrow_kind(m: hir::Mutability, allow_two_phase_borrow: bool) -> BorrowKind {
647-
match m {
648-
hir::MutMutable => BorrowKind::Mut { allow_two_phase_borrow },
649-
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+
}
650665
}
651666
}
652667

src/librustc_typeck/check/callee.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use hir::def::Def;
1616
use hir::def_id::{DefId, LOCAL_CRATE};
1717
use rustc::{infer, traits};
1818
use rustc::ty::{self, TyCtxt, TypeFoldable, Ty};
19-
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
19+
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
2020
use syntax::abi;
2121
use syntax::symbol::Symbol;
2222
use syntax_pos::Span;
@@ -176,8 +176,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
176176
let mut autoref = None;
177177
if borrow {
178178
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
179+
let mutbl = match mt.mutbl {
180+
hir::MutImmutable => AutoBorrowMutability::Immutable,
181+
hir::MutMutable => AutoBorrowMutability::Mutable {
182+
// For initial two-phase borrow
183+
// deployment, conservatively omit
184+
// overloaded function call ops.
185+
allow_two_phase_borrow: false,
186+
}
187+
};
179188
autoref = Some(Adjustment {
180-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
189+
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
181190
target: method.sig.inputs()[0]
182191
});
183192
}

src/librustc_typeck/check/coercion.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ use rustc::infer::{Coercion, InferResult, InferOk};
6868
use rustc::infer::type_variable::TypeVariableOrigin;
6969
use rustc::lint;
7070
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
71-
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
71+
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
7272
use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
7373
use rustc::ty::fold::TypeFoldable;
7474
use rustc::ty::error::TypeError;
@@ -421,8 +421,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
421421
ty::TyRef(r_borrow, _) => r_borrow,
422422
_ => span_bug!(span, "expected a ref type, got {:?}", ty),
423423
};
424+
let mutbl = match mt_b.mutbl {
425+
hir::MutImmutable => AutoBorrowMutability::Immutable,
426+
hir::MutMutable => AutoBorrowMutability::Mutable {
427+
// Deref-coercion is a case where we deliberately
428+
// disallow two-phase borrows in its initial
429+
// deployment; see discussion on PR #47489.
430+
allow_two_phase_borrow: false,
431+
}
432+
};
424433
adjustments.push(Adjustment {
425-
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
434+
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
426435
target: ty
427436
});
428437

@@ -461,11 +470,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
461470

462471
let coercion = Coercion(self.cause.span);
463472
let r_borrow = self.next_region_var(coercion);
473+
let mutbl = match mt_b.mutbl {
474+
hir::MutImmutable => AutoBorrowMutability::Immutable,
475+
hir::MutMutable => AutoBorrowMutability::Mutable {
476+
allow_two_phase_borrow: false,
477+
}
478+
};
464479
Some((Adjustment {
465480
kind: Adjust::Deref(None),
466481
target: mt_a.ty
467482
}, Adjustment {
468-
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
483+
kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
469484
target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut {
470485
mutbl: mt_b.mutbl,
471486
ty: mt_a.ty
@@ -871,6 +886,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
871886
] => {
872887
match self.node_ty(expr.hir_id).sty {
873888
ty::TyRef(_, mt_orig) => {
889+
let mutbl_adj: hir::Mutability = mutbl_adj.into();
874890
// Reborrow that we can safely ignore, because
875891
// the next adjustment can only be a Deref
876892
// which will be merged into it.

src/librustc_typeck/check/method/confirm.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc::ty::subst::Substs;
1717
use rustc::traits;
1818
use rustc::ty::{self, Ty};
1919
use rustc::ty::subst::Subst;
20-
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
20+
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, OverloadedDeref};
2121
use rustc::ty::fold::TypeFoldable;
2222
use rustc::infer::{self, InferOk};
2323
use syntax_pos::Span;
@@ -165,14 +165,22 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
165165
mutbl,
166166
ty: target
167167
});
168+
let mutbl = match mutbl {
169+
hir::MutImmutable => AutoBorrowMutability::Immutable,
170+
hir::MutMutable => AutoBorrowMutability::Mutable {
171+
// Method call receivers are the primary use case
172+
// for two-phase borrows.
173+
allow_two_phase_borrow: true,
174+
}
175+
};
168176
adjustments.push(Adjustment {
169177
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
170178
target
171179
});
172180

173181
if let Some(unsize_target) = pick.unsize {
174182
target = self.tcx.mk_ref(region, ty::TypeAndMut {
175-
mutbl,
183+
mutbl: mutbl.into(),
176184
ty: unsize_target
177185
});
178186
adjustments.push(Adjustment {
@@ -530,10 +538,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
530538
for adjustment in &mut adjustments[..] {
531539
if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
532540
debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
541+
let mutbl = match mutbl {
542+
hir::MutImmutable => AutoBorrowMutability::Immutable,
543+
hir::MutMutable => AutoBorrowMutability::Mutable {
544+
// For initial two-phase borrow
545+
// deployment, conservatively omit
546+
// overloaded operators.
547+
allow_two_phase_borrow: false,
548+
}
549+
};
533550
adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
534551
adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut {
535552
ty: source,
536-
mutbl
553+
mutbl: mutbl.into(),
537554
});
538555
}
539556
source = adjustment.target;

src/librustc_typeck/check/mod.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ use rustc::middle::region;
9696
use rustc::ty::subst::{Kind, Subst, Substs};
9797
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
9898
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
99-
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
99+
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
100100
use rustc::ty::fold::TypeFoldable;
101101
use rustc::ty::maps::Providers;
102102
use rustc::ty::util::{Representability, IntTypeExt};
@@ -2357,8 +2357,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
23572357

23582358
let mut adjustments = autoderef.adjust_steps(needs);
23592359
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
2360+
let mutbl = match mt.mutbl {
2361+
hir::MutImmutable => AutoBorrowMutability::Immutable,
2362+
hir::MutMutable => AutoBorrowMutability::Mutable {
2363+
// FIXME (#46747): arguably indexing is
2364+
// "just another kind of call"; perhaps it
2365+
// would be more consistent to allow
2366+
// two-phase borrows for .index()
2367+
// receivers here.
2368+
allow_two_phase_borrow: false,
2369+
}
2370+
};
23602371
adjustments.push(Adjustment {
2361-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
2372+
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
23622373
target: self.tcx.mk_ref(region, ty::TypeAndMut {
23632374
mutbl: mt.mutbl,
23642375
ty: adjusted_ty
@@ -3646,8 +3657,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
36463657
expr.span, oprnd_t, needs) {
36473658
let method = self.register_infer_ok_obligations(ok);
36483659
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
3660+
let mutbl = match mt.mutbl {
3661+
hir::MutImmutable => AutoBorrowMutability::Immutable,
3662+
hir::MutMutable => AutoBorrowMutability::Mutable {
3663+
// (It shouldn't actually matter for unary ops whether
3664+
// we enable two-phase borrows or not, since a unary
3665+
// op has no additional operands.)
3666+
allow_two_phase_borrow: false,
3667+
}
3668+
};
36493669
self.apply_adjustments(oprnd, vec![Adjustment {
3650-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
3670+
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
36513671
target: method.sig.inputs()[0]
36523672
}]);
36533673
}

src/librustc_typeck/check/op.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use super::{FnCtxt, Needs};
1414
use super::method::MethodCallee;
1515
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
1616
use rustc::ty::TypeVariants::{TyStr, TyRef};
17-
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
17+
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
1818
use rustc::infer::type_variable::TypeVariableOrigin;
1919
use errors;
2020
use syntax_pos::Span;
@@ -198,17 +198,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
198198
let by_ref_binop = !op.node.is_by_value();
199199
if is_assign == IsAssign::Yes || by_ref_binop {
200200
if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
201+
let mutbl = match mt.mutbl {
202+
hir::MutImmutable => AutoBorrowMutability::Immutable,
203+
hir::MutMutable => AutoBorrowMutability::Mutable {
204+
// For initial two-phase borrow
205+
// deployment, conservatively omit
206+
// overloaded binary ops.
207+
allow_two_phase_borrow: false,
208+
}
209+
};
201210
let autoref = Adjustment {
202-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
211+
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
203212
target: method.sig.inputs()[0]
204213
};
205214
self.apply_adjustments(lhs_expr, vec![autoref]);
206215
}
207216
}
208217
if by_ref_binop {
209218
if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty {
219+
let mutbl = match mt.mutbl {
220+
hir::MutImmutable => AutoBorrowMutability::Immutable,
221+
hir::MutMutable => AutoBorrowMutability::Mutable {
222+
// For initial two-phase borrow
223+
// deployment, conservatively omit
224+
// overloaded binary ops.
225+
allow_two_phase_borrow: false,
226+
}
227+
};
210228
let autoref = Adjustment {
211-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
229+
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
212230
target: method.sig.inputs()[1]
213231
};
214232
// HACK(eddyb) Bypass checks due to reborrows being in

src/librustc_typeck/check/regionck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
10631063
match *autoref {
10641064
adjustment::AutoBorrow::Ref(r, m) => {
10651065
self.link_region(expr.span, r,
1066-
ty::BorrowKind::from_mutbl(m), expr_cmt);
1066+
ty::BorrowKind::from_mutbl(m.into()), expr_cmt);
10671067
}
10681068

10691069
adjustment::AutoBorrow::RawPtr(m) => {

0 commit comments

Comments
 (0)