about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ich/impls_ty.rs14
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/ty/adjustment.rs17
-rw-r--r--src/librustc_lint/unused.rs6
-rw-r--r--src/librustc_mir/hair/cx/expr.rs33
-rw-r--r--src/librustc_typeck/check/callee.rs13
-rw-r--r--src/librustc_typeck/check/coercion.rs22
-rw-r--r--src/librustc_typeck/check/method/confirm.rs23
-rw-r--r--src/librustc_typeck/check/mod.rs26
-rw-r--r--src/librustc_typeck/check/op.rs24
-rw-r--r--src/librustc_typeck/check/regionck.rs2
11 files changed, 154 insertions, 28 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 107779ec3fa..d1e431597e7 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -163,6 +163,20 @@ impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
 impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
 impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
 
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::adjustment::AutoBorrowMutability {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::AutoBorrowMutability::Mutable { ref allow_two_phase_borrow } => {
+                allow_two_phase_borrow.hash_stable(hcx, hasher);
+            }
+            ty::adjustment::AutoBorrowMutability::Immutable => {}
+        }
+    }
+}
+
 impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
 
 impl_stable_hash_for!(enum ty::BorrowKind {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index c69005101c6..7db75a51668 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -760,7 +760,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                                      expr.span,
                                      cmt_base,
                                      r,
-                                     ty::BorrowKind::from_mutbl(m),
+                                     ty::BorrowKind::from_mutbl(m.into()),
                                      AutoRef);
             }
 
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index 96d69b4fba2..7579d95a8fe 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -120,9 +120,24 @@ impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
 }
 
 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+pub enum AutoBorrowMutability {
+    Mutable { allow_two_phase_borrow: bool },
+    Immutable,
+}
+
+impl From<AutoBorrowMutability> for hir::Mutability {
+    fn from(m: AutoBorrowMutability) -> Self {
+        match m {
+            AutoBorrowMutability::Mutable { .. } => hir::MutMutable,
+            AutoBorrowMutability::Immutable => hir::MutImmutable,
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub enum AutoBorrow<'tcx> {
     /// Convert from T to &T.
-    Ref(ty::Region<'tcx>, hir::Mutability),
+    Ref(ty::Region<'tcx>, AutoBorrowMutability),
 
     /// Convert from T to *T.
     RawPtr(hir::Mutability),
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 56f863ab3aa..439533fae49 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -437,8 +437,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
         for adj in cx.tables.expr_adjustments(e) {
             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
                 let msg = match m {
-                    hir::MutImmutable => "unnecessary allocation, use & instead",
-                    hir::MutMutable => "unnecessary allocation, use &mut instead"
+                    adjustment::AutoBorrowMutability::Immutable =>
+                        "unnecessary allocation, use & instead",
+                    adjustment::AutoBorrowMutability::Mutable { .. }=>
+                        "unnecessary allocation, use &mut instead"
                 };
                 cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
             }
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index e33147a915b..00ab2e45995 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
 use rustc::hir::def_id::LocalDefId;
@@ -112,7 +112,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 span,
                 kind: ExprKind::Borrow {
                     region: deref.region,
-                    borrow_kind: to_borrow_kind(deref.mutbl, true),
+                    borrow_kind: deref.mutbl.to_borrow_kind(),
                     arg: expr.to_ref(),
                 },
             };
@@ -122,7 +122,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
             ExprKind::Borrow {
                 region: r,
-                borrow_kind: to_borrow_kind(m, true),
+                borrow_kind: m.to_borrow_kind(),
                 arg: expr.to_ref(),
             }
         }
@@ -142,7 +142,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 span,
                 kind: ExprKind::Borrow {
                     region,
-                    borrow_kind: to_borrow_kind(m, true),
+                    borrow_kind: m.to_borrow_kind(),
                     arg: expr.to_ref(),
                 },
             };
@@ -288,7 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             };
             ExprKind::Borrow {
                 region,
-                borrow_kind: to_borrow_kind(mutbl, false),
+                borrow_kind: mutbl.to_borrow_kind(),
                 arg: expr.to_ref(),
             }
         }
@@ -643,10 +643,25 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     }
 }
 
-fn to_borrow_kind(m: hir::Mutability, allow_two_phase_borrow: bool) -> BorrowKind {
-    match m {
-        hir::MutMutable => BorrowKind::Mut { allow_two_phase_borrow },
-        hir::MutImmutable => BorrowKind::Shared,
+trait ToBorrowKind { fn to_borrow_kind(&self) -> BorrowKind; }
+
+impl ToBorrowKind for AutoBorrowMutability {
+    fn to_borrow_kind(&self) -> BorrowKind {
+        match *self {
+            AutoBorrowMutability::Mutable { allow_two_phase_borrow } =>
+                BorrowKind::Mut { allow_two_phase_borrow },
+            AutoBorrowMutability::Immutable =>
+                BorrowKind::Shared,
+        }
+    }
+}
+
+impl ToBorrowKind for hir::Mutability {
+    fn to_borrow_kind(&self) -> BorrowKind {
+        match *self {
+            hir::MutMutable => BorrowKind::Mut { allow_two_phase_borrow: false },
+            hir::MutImmutable => BorrowKind::Shared,
+        }
     }
 }
 
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 76df9be4838..3d61ffe3933 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -16,7 +16,7 @@ use hir::def::Def;
 use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::{infer, traits};
 use rustc::ty::{self, TyCtxt, TypeFoldable, Ty};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use syntax::abi;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -176,8 +176,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let mut autoref = None;
                     if borrow {
                         if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                            let mutbl = match mt.mutbl {
+                                hir::MutImmutable => AutoBorrowMutability::Immutable,
+                                hir::MutMutable => AutoBorrowMutability::Mutable {
+                                    // For initial two-phase borrow
+                                    // deployment, conservatively omit
+                                    // overloaded function call ops.
+                                    allow_two_phase_borrow: false,
+                                }
+                            };
                             autoref = Some(Adjustment {
-                                kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                                kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                                 target: method.sig.inputs()[0]
                             });
                         }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index d0280bf0b30..47e4b0272be 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -68,7 +68,7 @@ use rustc::infer::{Coercion, InferResult, InferOk};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::lint;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
@@ -421,8 +421,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             ty::TyRef(r_borrow, _) => r_borrow,
             _ => span_bug!(span, "expected a ref type, got {:?}", ty),
         };
+        let mutbl = match mt_b.mutbl {
+            hir::MutImmutable => AutoBorrowMutability::Immutable,
+            hir::MutMutable => AutoBorrowMutability::Mutable {
+                // Deref-coercion is a case where we deliberately
+                // disallow two-phase borrows in its initial
+                // deployment; see discussion on PR #47489.
+                allow_two_phase_borrow: false,
+            }
+        };
         adjustments.push(Adjustment {
-            kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
+            kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
             target: ty
         });
 
@@ -461,11 +470,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
                 let coercion = Coercion(self.cause.span);
                 let r_borrow = self.next_region_var(coercion);
+                let mutbl = match mt_b.mutbl {
+                    hir::MutImmutable => AutoBorrowMutability::Immutable,
+                    hir::MutMutable => AutoBorrowMutability::Mutable {
+                        allow_two_phase_borrow: false,
+                    }
+                };
                 Some((Adjustment {
                     kind: Adjust::Deref(None),
                     target: mt_a.ty
                 }, Adjustment {
-                    kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mt_b.mutbl)),
+                    kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
                     target:  self.tcx.mk_ref(r_borrow, ty::TypeAndMut {
                         mutbl: mt_b.mutbl,
                         ty: mt_a.ty
@@ -871,6 +886,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 ] => {
                     match self.node_ty(expr.hir_id).sty {
                         ty::TyRef(_, mt_orig) => {
+                            let mutbl_adj: hir::Mutability = mutbl_adj.into();
                             // Reborrow that we can safely ignore, because
                             // the next adjustment can only be a Deref
                             // which will be merged into it.
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 7f5b353f79e..20d58991496 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -17,7 +17,7 @@ use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty};
 use rustc::ty::subst::Subst;
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, OverloadedDeref};
 use rustc::ty::fold::TypeFoldable;
 use rustc::infer::{self, InferOk};
 use syntax_pos::Span;
@@ -165,6 +165,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                 mutbl,
                 ty: target
             });
+            let mutbl = match mutbl {
+                hir::MutImmutable => AutoBorrowMutability::Immutable,
+                hir::MutMutable => AutoBorrowMutability::Mutable {
+                    // Method call receivers are the primary use case
+                    // for two-phase borrows.
+                    allow_two_phase_borrow: true,
+                }
+            };
             adjustments.push(Adjustment {
                 kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                 target
@@ -172,7 +180,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
 
             if let Some(unsize_target) = pick.unsize {
                 target = self.tcx.mk_ref(region, ty::TypeAndMut {
-                    mutbl,
+                    mutbl: mutbl.into(),
                     ty: unsize_target
                 });
                 adjustments.push(Adjustment {
@@ -530,10 +538,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             for adjustment in &mut adjustments[..] {
                 if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
                     debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
+                    let mutbl = match mutbl {
+                        hir::MutImmutable => AutoBorrowMutability::Immutable,
+                        hir::MutMutable => AutoBorrowMutability::Mutable {
+                            // For initial two-phase borrow
+                            // deployment, conservatively omit
+                            // overloaded operators.
+                            allow_two_phase_borrow: false,
+                        }
+                    };
                     adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
                     adjustment.target = self.tcx.mk_ref(region, ty::TypeAndMut {
                         ty: source,
-                        mutbl
+                        mutbl: mutbl.into(),
                     });
                 }
                 source = adjustment.target;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 363d4a9dc0c..47bf085c9c0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -96,7 +96,7 @@ use rustc::middle::region;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
-use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
+use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::maps::Providers;
 use rustc::ty::util::{Representability, IntTypeExt};
@@ -2357,8 +2357,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 let mut adjustments = autoderef.adjust_steps(needs);
                 if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                    let mutbl = match mt.mutbl {
+                        hir::MutImmutable => AutoBorrowMutability::Immutable,
+                        hir::MutMutable => AutoBorrowMutability::Mutable {
+                            // FIXME (#46747): arguably indexing is
+                            // "just another kind of call"; perhaps it
+                            // would be more consistent to allow
+                            // two-phase borrows for .index()
+                            // receivers here.
+                            allow_two_phase_borrow: false,
+                        }
+                    };
                     adjustments.push(Adjustment {
-                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                         target: self.tcx.mk_ref(region, ty::TypeAndMut {
                             mutbl: mt.mutbl,
                             ty: adjusted_ty
@@ -3646,8 +3657,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 expr.span, oprnd_t, needs) {
                             let method = self.register_infer_ok_obligations(ok);
                             if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                                let mutbl = match mt.mutbl {
+                                    hir::MutImmutable => AutoBorrowMutability::Immutable,
+                                    hir::MutMutable => AutoBorrowMutability::Mutable {
+                                        // (It shouldn't actually matter for unary ops whether
+                                        // we enable two-phase borrows or not, since a unary
+                                        // op has no additional operands.)
+                                        allow_two_phase_borrow: false,
+                                    }
+                                };
                                 self.apply_adjustments(oprnd, vec![Adjustment {
-                                    kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                                    kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                                     target: method.sig.inputs()[0]
                                 }]);
                             }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 0698e3ecb6e..a6776a0fe86 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -14,7 +14,7 @@ use super::{FnCtxt, Needs};
 use super::method::MethodCallee;
 use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
 use rustc::ty::TypeVariants::{TyStr, TyRef};
-use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use errors;
 use syntax_pos::Span;
@@ -198,8 +198,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let by_ref_binop = !op.node.is_by_value();
                 if is_assign == IsAssign::Yes || by_ref_binop {
                     if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty {
+                        let mutbl = match mt.mutbl {
+                            hir::MutImmutable => AutoBorrowMutability::Immutable,
+                            hir::MutMutable => AutoBorrowMutability::Mutable {
+                                // For initial two-phase borrow
+                                // deployment, conservatively omit
+                                // overloaded binary ops.
+                                allow_two_phase_borrow: false,
+                            }
+                        };
                         let autoref = Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                             target: method.sig.inputs()[0]
                         };
                         self.apply_adjustments(lhs_expr, vec![autoref]);
@@ -207,8 +216,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 if by_ref_binop {
                     if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty {
+                        let mutbl = match mt.mutbl {
+                            hir::MutImmutable => AutoBorrowMutability::Immutable,
+                            hir::MutMutable => AutoBorrowMutability::Mutable {
+                                // For initial two-phase borrow
+                                // deployment, conservatively omit
+                                // overloaded binary ops.
+                                allow_two_phase_borrow: false,
+                            }
+                        };
                         let autoref = Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)),
+                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
                             target: method.sig.inputs()[1]
                         };
                         // HACK(eddyb) Bypass checks due to reborrows being in
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 64063ec5bed..b5bf59fef9a 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1063,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         match *autoref {
             adjustment::AutoBorrow::Ref(r, m) => {
                 self.link_region(expr.span, r,
-                                 ty::BorrowKind::from_mutbl(m), expr_cmt);
+                                 ty::BorrowKind::from_mutbl(m.into()), expr_cmt);
             }
 
             adjustment::AutoBorrow::RawPtr(m) => {