1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
//@ revisions: base
//@ unused-revision-names: g2p
//@[g2p]compile-flags: -Z two-phase-beyond-autoref
// 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
// receivers (namely, in many cases demonstrated below, the error
// would not arise).
use std::ops::{Index, IndexMut};
fn foo(x: &mut u32, y: u32) {
*x += y;
}
fn deref_coercion(x: &mut u32) {
foo(x, *x);
// Above error is a known limitation of AST borrowck
}
// 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] ExprKind::Index and ExprKind::Unary 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));
//~^ 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));
//~^ ERROR use of moved value: `f`
}
fn twice_ten_om(f: &mut dyn FnMut(i32) -> i32) {
f(f(10));
//~^ ERROR cannot borrow `*f` as mutable more than once at a time
}
fn twice_ten_oi(f: &mut dyn Fn(i32) -> i32) {
f(f(10));
}
fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) {
f(f(10));
//~^ ERROR use of moved value: `f`
}
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];
}
fn coerce_unsized() {
let mut a = [1, 2, 3];
// This is not okay.
double_access(&mut a, &a);
//~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
// But this is okay.
a.m(a.i(10));
// Above error is an expected limitation of AST borrowck
}
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;
//~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
// Should be accepted with g2p
i[3] = i[4];
i[i[3]] = i[4];
//~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
// Should be accepted with g2p
}
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());
// Error above is an expected limitation of AST borrowck
// (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));
// Error above is an expected limitation of AST borrowck
let mut t = T;
t.m(t.i(10));
// Error above is an expected limitation of AST borrowck
coerce_unsized();
coerce_index_op();
}
|