rust/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs

215 lines
7.7 KiB
Rust
Raw Normal View History

// 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: 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
2018-03-05 01:44:10 -06:00
//[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll -Z two-phase-beyond-autoref
2018-03-05 01:44:10 -06:00
// the above revision is disabled until two-phase-beyond-autoref support is better
// This is a test checking that when we limit two-phase borrows to
// method receivers, we do not let other kinds of auto-ref to leak
// through.
//
// The g2p revision illustrates the "undesirable" behavior you would
// otherwise observe without limiting the phasing to autoref on method
2018-02-06 09:47:38 -06:00
// receivers (namely, in many cases demonstrated below, the error
// would not arise).
// (If we revise the compiler or this test so that the g2p revision
// passes, turn the `rustc_attrs` feature back on and tag the `fn
// main` with `#[rustc_error]` so that this remains a valid
// compile-fail test.)
//
// #![feature(rustc_attrs)]
use std::ops::{Index, IndexMut};
2018-02-06 09:47:38 -06:00
fn foo(x: &mut u32, y: u32) {
*x += y;
}
fn deref_coercion(x: &mut u32) {
foo(x, *x);
//[ast]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
// Above error is a known limitation of AST borrowck
}
2018-02-06 09:47:38 -06:00
// While adding a flag to adjustments (indicating whether they
// should support two-phase borrows, here are the cases I
// encountered:
//
// - [x] Resolving overloaded_call_traits (call, call_mut, call_once)
// - [x] deref_coercion (shown above)
// - [x] coerce_unsized e.g. `&[T; n]`, `&mut [T; n] -> &[T]`,
// `&mut [T; n] -> &mut [T]`, `&Concrete -> &Trait`
// - [x] Method Call Receivers (the case we want to support!)
// - [x] ExprIndex and ExprUnary Deref; only need to handle coerce_index_op
// - [x] overloaded_binops
fn overloaded_call_traits() {
// Regarding overloaded call traits, note that there is no
// scenario where adding two-phase borrows should "fix" these
// cases, because either we will resolve both invocations to
// `call_mut` (in which case the inner call requires a mutable
// borrow which will conflict with the outer reservation), or we
// will resolve both to `call` (which will just work, regardless
// of two-phase borrow support), or we will resolve both to
// `call_once` (in which case the inner call requires moving the
// receiver, invalidating the outer call).
fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
f(f(10));
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
2018-03-05 01:44:10 -06:00
//[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
2018-02-06 09:47:38 -06:00
}
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`
//[ast]~^^^^ ERROR use of moved value: `*f`
2018-02-06 09:47:38 -06:00
}
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
2018-03-05 01:44:10 -06:00
//[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
2018-02-06 09:47:38 -06:00
}
fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
f(f(10));
}
fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) {
f(f(10));
//[lxl]~^ ERROR cannot move a value of type
//[lxl]~^^ ERROR cannot move a value of type
//[lxl]~^^^ ERROR use of moved value: `*f`
//[nll]~^^^^ ERROR cannot move a value of type
//[nll]~^^^^^ ERROR cannot move a value of type
//[nll]~^^^^^^ ERROR use of moved value: `*f`
//[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`
2018-02-06 09:47:38 -06:00
}
twice_ten_sm(&mut |x| x + 1);
twice_ten_si(&mut |x| x + 1);
twice_ten_so(Box::new(|x| x + 1));
twice_ten_om(&mut |x| x + 1);
twice_ten_oi(&mut |x| x + 1);
twice_ten_oo(Box::new(|x| x + 1));
}
trait TwoMethods {
fn m(&mut self, x: i32) -> i32 { x + 1 }
fn i(&self, x: i32) -> i32 { x + 1 }
}
struct T;
impl TwoMethods for T { }
struct S;
impl S {
fn m(&mut self, x: i32) -> i32 { x + 1 }
fn i(&self, x: i32) -> i32 { x + 1 }
}
impl TwoMethods for [i32; 3] { }
fn double_access<X: Copy>(m: &mut [X], s: &[X]) {
m[0] = s[1];
}
2018-02-06 09:47:38 -06:00
fn coerce_unsized() {
let mut a = [1, 2, 3];
// 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]
//[ast]~^^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
2018-02-06 09:47:38 -06:00
// 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
2018-02-06 09:47:38 -06:00
}
struct I(i32);
impl Index<i32> for I {
type Output = i32;
fn index(&self, _: i32) -> &i32 {
&self.0
}
}
impl IndexMut<i32> for I {
fn index_mut(&mut self, _: i32) -> &mut i32 {
&mut self.0
}
}
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]
//[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
2018-02-06 09:47:38 -06:00
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]
//[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
2018-02-06 09:47:38 -06:00
}
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
2018-02-06 09:47:38 -06:00
// (as a rule, pnkfelix does not like to write tests with dead code.)
deref_coercion(&mut 5);
overloaded_call_traits();
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
2018-02-06 09:47:38 -06:00
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
2018-02-06 09:47:38 -06:00
coerce_unsized();
coerce_index_op();
}