Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow two-phase borrows of &mut self in ops #48197

Merged
merged 2 commits into from
Feb 25, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions src/librustc_typeck/check/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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,
// Allow two-phase borrows for binops in initial deployment
// since they desugar to methods
allow_two_phase_borrow: true,
}
};
let autoref = Adjustment {
Expand All @@ -219,10 +218,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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,
// Allow two-phase borrows for binops in initial deployment
// since they desugar to methods
allow_two_phase_borrow: true,
}
};
let autoref = Adjustment {
Expand Down
53 changes: 0 additions & 53 deletions src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
// #![feature(rustc_attrs)]

use std::ops::{Index, IndexMut};
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};

// This is case outlined by Niko that we want to ensure we reject
// (at least initially).
Expand Down Expand Up @@ -186,56 +184,6 @@ fn coerce_index_op() {
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
}

struct A(i32);

macro_rules! trivial_binop {
($Trait:ident, $m:ident) => {
impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
}
}

trivial_binop!(AddAssign, add_assign);
trivial_binop!(SubAssign, sub_assign);
trivial_binop!(MulAssign, mul_assign);
trivial_binop!(DivAssign, div_assign);
trivial_binop!(RemAssign, rem_assign);
trivial_binop!(BitAndAssign, bitand_assign);
trivial_binop!(BitOrAssign, bitor_assign);
trivial_binop!(BitXorAssign, bitxor_assign);
trivial_binop!(ShlAssign, shl_assign);
trivial_binop!(ShrAssign, shr_assign);

fn overloaded_binops() {
let mut a = A(10);
a += a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a -= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a *= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a /= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a &= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a |= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a ^= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a <<= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
a >>= a.0;
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
}

fn main() {

// As a reminder, this is the basic case we want to ensure we handle.
Expand All @@ -256,5 +204,4 @@ fn main() {

coerce_unsized();
coerce_index_op();
overloaded_binops();
}
49 changes: 49 additions & 0 deletions src/test/run-pass/borrowck/two-phase-bin-ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2018 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this lxl revision is still using the MIR borrowck. Can we add a revision that tests the existing borrowck (possibly replacing the existing lxl)? e.g.

// Test that NLL and the older, AST-based checker both accept these constructions:
// revisions: ast nll

#![cfg_attr(nll, feature(nll))]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I don't know that we care so much about the MIR-based borrowck without NLL enabled)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, but now I'm really confused about the arguments specified here

//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows

In any case, I've dropped those args now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I think that felix was specifically targeting MIR borrowck w/o NLL. But in this case, I don't think we need to, but I think it's important to show that we are preserving the current behavior in terms of what code is accepted.


#![cfg_attr(nll, feature(nll))]

use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};

struct A(i32);

macro_rules! trivial_binop {
($Trait:ident, $m:ident) => {
impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
}
}

trivial_binop!(AddAssign, add_assign);
trivial_binop!(SubAssign, sub_assign);
trivial_binop!(MulAssign, mul_assign);
trivial_binop!(DivAssign, div_assign);
trivial_binop!(RemAssign, rem_assign);
trivial_binop!(BitAndAssign, bitand_assign);
trivial_binop!(BitOrAssign, bitor_assign);
trivial_binop!(BitXorAssign, bitxor_assign);
trivial_binop!(ShlAssign, shl_assign);
trivial_binop!(ShrAssign, shr_assign);

fn main() {
let mut a = A(10);
a += a.0;
a -= a.0;
a *= a.0;
a /= a.0;
a &= a.0;
a |= a.0;
a ^= a.0;
a <<= a.0;
a >>= a.0;
}