Auto merge of #49348 - bobtwinkles:extend_2pb, r=nikomatsakis
Extend two-phase borrows to apply to method receiver autorefs Fixes #48598 by permitting two-phase borrows on the autorefs created when functions and methods.
This commit is contained in:
commit
b12af86a77
12 changed files with 155 additions and 57 deletions
|
|
@ -188,6 +188,10 @@ for ty::adjustment::Adjust<'gcx> {
|
|||
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_stable_hash_for!(enum ty::adjustment::AllowTwoPhase {
|
||||
Yes,
|
||||
No
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::adjustment::AutoBorrowMutability {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
|
|
|
|||
|
|
@ -119,9 +119,27 @@ impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// At least for initial deployment, we want to limit two-phase borrows to
|
||||
/// only a few specific cases. Right now, those mostly "things that desugar"
|
||||
/// into method calls
|
||||
/// - using x.some_method() syntax, where some_method takes &mut self
|
||||
/// - using Foo::some_method(&mut x, ...) syntax
|
||||
/// - binary assignment operators (+=, -=, *=, etc.)
|
||||
/// Anything else should be rejected until generalized two phase borrow support
|
||||
/// is implemented. Right now, dataflow can't handle the general case where there
|
||||
/// is more than one use of a mutable borrow, and we don't want to accept too much
|
||||
/// new code via two-phase borrows, so we try to limit where we create two-phase
|
||||
/// capable mutable borrows.
|
||||
/// See #49434 for tracking.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum AllowTwoPhase {
|
||||
Yes,
|
||||
No
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum AutoBorrowMutability {
|
||||
Mutable { allow_two_phase_borrow: bool },
|
||||
Mutable { allow_two_phase_borrow: AllowTwoPhase },
|
||||
Immutable,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -662,9 +662,13 @@ trait ToBorrowKind { fn to_borrow_kind(&self) -> BorrowKind; }
|
|||
|
||||
impl ToBorrowKind for AutoBorrowMutability {
|
||||
fn to_borrow_kind(&self) -> BorrowKind {
|
||||
use rustc::ty::adjustment::AllowTwoPhase;
|
||||
match *self {
|
||||
AutoBorrowMutability::Mutable { allow_two_phase_borrow } =>
|
||||
BorrowKind::Mut { allow_two_phase_borrow },
|
||||
BorrowKind::Mut { allow_two_phase_borrow: match allow_two_phase_borrow {
|
||||
AllowTwoPhase::Yes => true,
|
||||
AllowTwoPhase::No => false
|
||||
}},
|
||||
AutoBorrowMutability::Immutable =>
|
||||
BorrowKind::Shared,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, AutoBorrowMutability};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
use syntax::abi;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -182,7 +182,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// For initial two-phase borrow
|
||||
// deployment, conservatively omit
|
||||
// overloaded function call ops.
|
||||
allow_two_phase_borrow: false,
|
||||
allow_two_phase_borrow: AllowTwoPhase::No,
|
||||
}
|
||||
};
|
||||
autoref = Some(Adjustment {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ use rustc::hir;
|
|||
use rustc::session::Session;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::adjustment::AllowTwoPhase;
|
||||
use rustc::ty::cast::{CastKind, CastTy};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::middle::lang_items;
|
||||
|
|
@ -434,7 +435,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
|||
let f = self.expr_ty.fn_sig(fcx.tcx);
|
||||
let res = fcx.try_coerce(self.expr,
|
||||
self.expr_ty,
|
||||
fcx.tcx.mk_fn_ptr(f));
|
||||
fcx.tcx.mk_fn_ptr(f),
|
||||
AllowTwoPhase::No);
|
||||
if !res.is_ok() {
|
||||
return Err(CastError::NonScalar);
|
||||
}
|
||||
|
|
@ -616,7 +618,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
|
|||
}
|
||||
|
||||
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
|
||||
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ use rustc::hir::def_id::DefId;
|
|||
use rustc::infer::{Coercion, InferResult, InferOk};
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::error::TypeError;
|
||||
|
|
@ -84,6 +84,13 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
|||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
use_lub: bool,
|
||||
/// Determines whether or not allow_two_phase_borrow is set on any
|
||||
/// autoref adjustments we create while coercing. We don't want to
|
||||
/// allow deref coercions to create two-phase borrows, at least initially,
|
||||
/// but we do need two-phase borrows for function argument reborrows.
|
||||
/// See #47489 and #48598
|
||||
/// See docs on the "AllowTwoPhase" type for a more detailed discussion
|
||||
allow_two_phase: AllowTwoPhase,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
|
||||
|
|
@ -123,10 +130,13 @@ fn success<'tcx>(adj: Vec<Adjustment<'tcx>>,
|
|||
}
|
||||
|
||||
impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
|
||||
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
allow_two_phase: AllowTwoPhase) -> Self {
|
||||
Coerce {
|
||||
fcx,
|
||||
cause,
|
||||
allow_two_phase,
|
||||
use_lub: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -423,10 +433,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
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,
|
||||
allow_two_phase_borrow: self.allow_two_phase,
|
||||
}
|
||||
};
|
||||
adjustments.push(Adjustment {
|
||||
|
|
@ -472,7 +479,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
|||
let mutbl = match mt_b.mutbl {
|
||||
hir::MutImmutable => AutoBorrowMutability::Immutable,
|
||||
hir::MutMutable => AutoBorrowMutability::Mutable {
|
||||
allow_two_phase_borrow: false,
|
||||
// We don't allow two-phase borrows here, at least for initial
|
||||
// implementation. If it happens that this coercion is a function argument,
|
||||
// the reborrow in coerce_borrowed_ptr will pick it up.
|
||||
allow_two_phase_borrow: AllowTwoPhase::No,
|
||||
}
|
||||
};
|
||||
Some((Adjustment {
|
||||
|
|
@ -750,13 +760,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn try_coerce(&self,
|
||||
expr: &hir::Expr,
|
||||
expr_ty: Ty<'tcx>,
|
||||
target: Ty<'tcx>)
|
||||
target: Ty<'tcx>,
|
||||
allow_two_phase: AllowTwoPhase)
|
||||
-> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let source = self.resolve_type_vars_with_obligations(expr_ty);
|
||||
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
|
||||
|
||||
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
let coerce = Coerce::new(self, cause, allow_two_phase);
|
||||
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
||||
|
||||
let (adjustments, _) = self.register_infer_ok_obligations(ok);
|
||||
|
|
@ -770,7 +781,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
debug!("coercion::can({:?} -> {:?})", source, target);
|
||||
|
||||
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||
let coerce = Coerce::new(self, cause);
|
||||
// We don't ever need two-phase here since we throw out the result of the coercion
|
||||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
|
||||
self.probe(|_| coerce.coerce(source, target)).is_ok()
|
||||
}
|
||||
|
||||
|
|
@ -839,7 +851,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
return Ok(fn_ptr);
|
||||
}
|
||||
|
||||
let mut coerce = Coerce::new(self, cause.clone());
|
||||
// Configure a Coerce instance to compute the LUB.
|
||||
// We don't allow two-phase borrows on any autorefs this creates since we
|
||||
// probably aren't processing function arguments here and even if we were,
|
||||
// they're going to get autorefed again anyway and we can apply 2-phase borrows
|
||||
// at that time.
|
||||
let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No);
|
||||
coerce.use_lub = true;
|
||||
|
||||
// First try to coerce the new expression to the type of the previous ones,
|
||||
|
|
@ -1105,7 +1122,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
|
|||
if self.pushed == 0 {
|
||||
// Special-case the first expression we are coercing.
|
||||
// To be honest, I'm not entirely sure why we do this.
|
||||
fcx.try_coerce(expression, expression_ty, self.expected_ty)
|
||||
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
|
||||
fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No)
|
||||
} else {
|
||||
match self.expressions {
|
||||
Expressions::Dynamic(ref exprs) =>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use rustc::hir::def::Def;
|
|||
use rustc::hir::map::NodeItem;
|
||||
use rustc::hir::{Item, ItemConst, print};
|
||||
use rustc::ty::{self, Ty, AssociatedItem};
|
||||
use rustc::ty::adjustment::AllowTwoPhase;
|
||||
use errors::{DiagnosticBuilder, CodeMapper};
|
||||
|
||||
use super::method::probe;
|
||||
|
|
@ -80,9 +81,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn demand_coerce(&self,
|
||||
expr: &hir::Expr,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>)
|
||||
expected: Ty<'tcx>,
|
||||
allow_two_phase: AllowTwoPhase)
|
||||
-> Ty<'tcx> {
|
||||
let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected);
|
||||
let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected, allow_two_phase);
|
||||
if let Some(mut err) = err {
|
||||
err.emit();
|
||||
}
|
||||
|
|
@ -97,11 +99,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn demand_coerce_diag(&self,
|
||||
expr: &hir::Expr,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>)
|
||||
expected: Ty<'tcx>,
|
||||
allow_two_phase: AllowTwoPhase)
|
||||
-> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
|
||||
let expected = self.resolve_type_vars_with_obligations(expected);
|
||||
|
||||
let e = match self.try_coerce(expr, checked_ty, expected) {
|
||||
let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) {
|
||||
Ok(ty) => return (ty, None),
|
||||
Err(e) => e
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ 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, AutoBorrowMutability, OverloadedDeref};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
|
||||
use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::infer::{self, InferOk};
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -170,7 +171,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
|||
hir::MutMutable => AutoBorrowMutability::Mutable {
|
||||
// Method call receivers are the primary use case
|
||||
// for two-phase borrows.
|
||||
allow_two_phase_borrow: true,
|
||||
allow_two_phase_borrow: AllowTwoPhase::Yes,
|
||||
}
|
||||
};
|
||||
adjustments.push(Adjustment {
|
||||
|
|
@ -544,7 +545,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
|||
// For initial two-phase borrow
|
||||
// deployment, conservatively omit
|
||||
// overloaded operators.
|
||||
allow_two_phase_borrow: false,
|
||||
allow_two_phase_borrow: AllowTwoPhase::No,
|
||||
}
|
||||
};
|
||||
adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ use rustc::mir::interpret::{GlobalId};
|
|||
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
|
||||
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::maps::Providers;
|
||||
use rustc::ty::util::{Representability, IntTypeExt, Discr};
|
||||
|
|
@ -2377,12 +2377,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
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,
|
||||
// Indexing can be desugared to a method call,
|
||||
// so maybe we could use two-phase here.
|
||||
// See the documentation of AllowTwoPhase for why that's
|
||||
// not the case today.
|
||||
allow_two_phase_borrow: AllowTwoPhase::No,
|
||||
}
|
||||
};
|
||||
adjustments.push(Adjustment {
|
||||
|
|
@ -2685,7 +2684,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// to, which is `expected_ty` if `rvalue_hint` returns an
|
||||
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
|
||||
let coerce_ty = expected.and_then(|e| e.only_has_type(self));
|
||||
self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
|
||||
// We're processing function arguments so we definitely want to use
|
||||
// two-phase borrows.
|
||||
self.demand_coerce(&arg,
|
||||
checked_ty,
|
||||
coerce_ty.unwrap_or(formal_ty),
|
||||
AllowTwoPhase::Yes);
|
||||
|
||||
// 3. Relate the expected type and the formal one,
|
||||
// if the expected type was used for the coercion.
|
||||
|
|
@ -2847,7 +2851,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
expr,
|
||||
ExpectHasType(expected),
|
||||
needs);
|
||||
self.demand_coerce(expr, ty, expected)
|
||||
// checks don't need two phase
|
||||
self.demand_coerce(expr, ty, expected, AllowTwoPhase::No)
|
||||
}
|
||||
|
||||
fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
|
||||
|
|
@ -3674,7 +3679,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// (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,
|
||||
allow_two_phase_borrow: AllowTwoPhase::No,
|
||||
}
|
||||
};
|
||||
self.apply_adjustments(oprnd, vec![Adjustment {
|
||||
|
|
@ -4138,7 +4143,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
let base_t = self.structurally_resolved_type(expr.span, base_t);
|
||||
match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
|
||||
Some((index_ty, element_ty)) => {
|
||||
self.demand_coerce(idx, idx_t, index_ty);
|
||||
// two-phase not needed because index_ty is never mutable
|
||||
self.demand_coerce(idx, idx_t, index_ty, AllowTwoPhase::No);
|
||||
element_ty
|
||||
}
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -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, TyAdt};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use errors;
|
||||
use syntax_pos::Span;
|
||||
|
|
@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
hir::MutMutable => AutoBorrowMutability::Mutable {
|
||||
// Allow two-phase borrows for binops in initial deployment
|
||||
// since they desugar to methods
|
||||
allow_two_phase_borrow: true,
|
||||
allow_two_phase_borrow: AllowTwoPhase::Yes,
|
||||
}
|
||||
};
|
||||
let autoref = Adjustment {
|
||||
|
|
@ -220,7 +220,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
hir::MutMutable => AutoBorrowMutability::Mutable {
|
||||
// Allow two-phase borrows for binops in initial deployment
|
||||
// since they desugar to methods
|
||||
allow_two_phase_borrow: true,
|
||||
allow_two_phase_borrow: AllowTwoPhase::Yes,
|
||||
}
|
||||
};
|
||||
let autoref = Adjustment {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: lxl nll
|
||||
// revisions: ast lxl nll
|
||||
//[ast]compile-flags:
|
||||
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
|
||||
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
|
||||
|
||||
|
|
@ -33,17 +34,14 @@
|
|||
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
// This is case outlined by Niko that we want to ensure we reject
|
||||
// (at least initially).
|
||||
|
||||
fn foo(x: &mut u32, y: u32) {
|
||||
*x += y;
|
||||
}
|
||||
|
||||
fn deref_coercion(x: &mut u32) {
|
||||
foo(x, *x);
|
||||
//[lxl]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
|
||||
//[nll]~^^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
|
||||
//[ast]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
|
||||
// Above error is a known limitation of AST borrowck
|
||||
}
|
||||
|
||||
// While adding a flag to adjustments (indicating whether they
|
||||
|
|
@ -74,22 +72,25 @@ fn overloaded_call_traits() {
|
|||
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[nll]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[ast]~^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
}
|
||||
fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
|
||||
f(f(10));
|
||||
}
|
||||
fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
|
||||
f(f(10));
|
||||
//[lxl]~^ ERROR use of moved value: `*f`
|
||||
//[nll]~^^ ERROR use of moved value: `*f`
|
||||
//[g2p]~^^^ ERROR use of moved value: `*f`
|
||||
//[lxl]~^ ERROR use of moved value: `*f`
|
||||
//[nll]~^^ ERROR use of moved value: `*f`
|
||||
//[g2p]~^^^ ERROR use of moved value: `*f`
|
||||
//[ast]~^^^^ ERROR use of moved value: `*f`
|
||||
}
|
||||
|
||||
fn twice_ten_om(f: &mut FnMut(i32) -> i32) {
|
||||
f(f(10));
|
||||
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[nll]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
//[ast]~^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
|
||||
}
|
||||
fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
|
||||
f(f(10));
|
||||
|
|
@ -105,6 +106,7 @@ fn overloaded_call_traits() {
|
|||
//[g2p]~^^^^^^^ ERROR cannot move a value of type
|
||||
//[g2p]~^^^^^^^^ ERROR cannot move a value of type
|
||||
//[g2p]~^^^^^^^^^ ERROR use of moved value: `*f`
|
||||
//[ast]~^^^^^^^^^^ ERROR use of moved value: `*f`
|
||||
}
|
||||
|
||||
twice_ten_sm(&mut |x| x + 1);
|
||||
|
|
@ -142,12 +144,15 @@ fn coerce_unsized() {
|
|||
|
||||
// This is not okay.
|
||||
double_access(&mut a, &a);
|
||||
//[lxl]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[nll]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[g2p]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[lxl]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[nll]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[g2p]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[ast]~^^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
|
||||
// But this is okay.
|
||||
a.m(a.i(10));
|
||||
//[ast]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
|
||||
// Above error is an expected limitation of AST borrowck
|
||||
}
|
||||
|
||||
struct I(i32);
|
||||
|
|
@ -168,14 +173,16 @@ impl IndexMut<i32> for I {
|
|||
fn coerce_index_op() {
|
||||
let mut i = I(10);
|
||||
i[i[3]] = 4;
|
||||
//[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
|
||||
i[3] = i[4];
|
||||
|
||||
i[i[3]] = i[4];
|
||||
//[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
//[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
@ -183,6 +190,8 @@ fn main() {
|
|||
// As a reminder, this is the basic case we want to ensure we handle.
|
||||
let mut v = vec![1, 2, 3];
|
||||
v.push(v.len());
|
||||
//[ast]~^ ERROR cannot borrow `v` as immutable because it is also borrowed as mutable [E0502]
|
||||
// Error above is an expected limitation of AST borrowck
|
||||
|
||||
// (as a rule, pnkfelix does not like to write tests with dead code.)
|
||||
|
||||
|
|
@ -192,9 +201,13 @@ fn main() {
|
|||
|
||||
let mut s = S;
|
||||
s.m(s.i(10));
|
||||
//[ast]~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable [E0502]
|
||||
// Error above is an expected limitation of AST borrowck
|
||||
|
||||
let mut t = T;
|
||||
t.m(t.i(10));
|
||||
//[ast]~^ ERROR cannot borrow `t` as immutable because it is also borrowed as mutable [E0502]
|
||||
// Error above is an expected limitation of AST borrowck
|
||||
|
||||
coerce_unsized();
|
||||
coerce_index_op();
|
||||
|
|
|
|||
29
src/test/ui/borrowck/two-phase-method-receivers.rs
Normal file
29
src/test/ui/borrowck/two-phase-method-receivers.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: lxl nll
|
||||
//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
|
||||
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
|
||||
|
||||
// run-pass
|
||||
|
||||
struct Foo<'a> {
|
||||
x: &'a i32
|
||||
}
|
||||
|
||||
impl<'a> Foo<'a> {
|
||||
fn method(&mut self, _: &i32) {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = &mut Foo { x: &22 };
|
||||
Foo::method(a, a.x);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue