Skip to content

Commit b55cd8c

Browse files
committed
Fleshed out the test a lot more.
1 parent 81b93fa commit b55cd8c

File tree

1 file changed

+230
-9
lines changed

1 file changed

+230
-9
lines changed

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

+230-9
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,248 @@
1313
//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
1414
//[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll -Z two-phase-beyond-autoref
1515

16-
#![feature(rustc_attrs)]
17-
1816
// This is a test checking that when we limit two-phase borrows to
1917
// method receivers, we do not let other kinds of auto-ref to leak
2018
// through.
2119
//
2220
// The g2p revision illustrates the "undesirable" behavior you would
2321
// otherwise observe without limiting the phasing to autoref on method
24-
// receivers (namely, that the test would pass).
22+
// receivers (namely, in many cases demonstrated below, the error
23+
// would not arise).
24+
25+
// (If we revise the compiler or this test so that the g2p revision
26+
// passes, turn the `rustc_attrs` feature back on and tag the `fn
27+
// main` with `#[rustc_error]` so that this remains a valid
28+
// compile-fail test.)
29+
//
30+
// #![feature(rustc_attrs)]
31+
32+
use std::ops::{Index, IndexMut};
33+
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
34+
use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
2535

26-
fn bar(x: &mut u32) {
36+
// This is case outlined by Niko that we want to ensure we reject
37+
// (at least initially).
38+
39+
fn foo(x: &mut u32, y: u32) {
40+
*x += y;
41+
}
42+
43+
fn deref_coercion(x: &mut u32) {
2744
foo(x, *x);
2845
//[lxl]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
2946
//[nll]~^^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
3047
}
3148

32-
fn foo(x: &mut u32, y: u32) {
33-
*x += y;
49+
// While adding a flag to adjustments (indicating whether they
50+
// should support two-phase borrows, here are the cases I
51+
// encountered:
52+
//
53+
// - [x] Resolving overloaded_call_traits (call, call_mut, call_once)
54+
// - [x] deref_coercion (shown above)
55+
// - [x] coerce_unsized e.g. `&[T; n]`, `&mut [T; n] -> &[T]`,
56+
// `&mut [T; n] -> &mut [T]`, `&Concrete -> &Trait`
57+
// - [x] Method Call Receivers (the case we want to support!)
58+
// - [x] ExprIndex and ExprUnary Deref; only need to handle coerce_index_op
59+
// - [x] overloaded_binops
60+
61+
fn overloaded_call_traits() {
62+
// Regarding overloaded call traits, note that there is no
63+
// scenario where adding two-phase borrows should "fix" these
64+
// cases, because either we will resolve both invocations to
65+
// `call_mut` (in which case the inner call requires a mutable
66+
// borrow which will conflict with the outer reservation), or we
67+
// will resolve both to `call` (which will just work, regardless
68+
// of two-phase borrow support), or we will resolve both to
69+
// `call_once` (in which case the inner call requires moving the
70+
// receiver, invalidating the outer call).
71+
72+
fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
73+
f(f(10));
74+
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
75+
//[lxl]~| ERROR cannot borrow `*f` as mutable more than once at a time
76+
//[nll]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
77+
//[nll]~| ERROR cannot borrow `*f` as mutable more than once at a time
78+
//[g2p]~^^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
79+
}
80+
fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
81+
f(f(10));
82+
}
83+
fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
84+
f(f(10));
85+
//[lxl]~^ ERROR use of moved value: `*f`
86+
//[nll]~^^ ERROR use of moved value: `*f`
87+
//[g2p]~^^^ ERROR use of moved value: `*f`
88+
}
89+
90+
fn twice_ten_om(f: &mut FnMut(i32) -> i32) {
91+
f(f(10));
92+
//[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
93+
//[lxl]~| ERROR cannot borrow `*f` as mutable more than once at a time
94+
//[nll]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
95+
//[nll]~| ERROR cannot borrow `*f` as mutable more than once at a time
96+
//[g2p]~^^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
97+
}
98+
fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
99+
f(f(10));
100+
}
101+
fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) {
102+
f(f(10));
103+
//[lxl]~^ ERROR cannot move a value of type
104+
//[lxl]~^^ ERROR cannot move a value of type
105+
//[lxl]~^^^ ERROR use of moved value: `*f`
106+
//[nll]~^^^^ ERROR cannot move a value of type
107+
//[nll]~^^^^^ ERROR cannot move a value of type
108+
//[nll]~^^^^^^ ERROR cannot move a value of type
109+
//[nll]~^^^^^^^ ERROR cannot move a value of type
110+
//[nll]~^^^^^^^^ ERROR use of moved value: `*f`
111+
//[g2p]~^^^^^^^^^ ERROR cannot move a value of type
112+
//[g2p]~^^^^^^^^^^ ERROR cannot move a value of type
113+
//[g2p]~^^^^^^^^^^^ ERROR cannot move a value of type
114+
//[g2p]~^^^^^^^^^^^^ ERROR cannot move a value of type
115+
//[g2p]~^^^^^^^^^^^^^ ERROR use of moved value: `*f`
116+
}
117+
118+
twice_ten_sm(&mut |x| x + 1);
119+
twice_ten_si(&mut |x| x + 1);
120+
twice_ten_so(Box::new(|x| x + 1));
121+
twice_ten_om(&mut |x| x + 1);
122+
twice_ten_oi(&mut |x| x + 1);
123+
twice_ten_oo(Box::new(|x| x + 1));
124+
}
125+
126+
trait TwoMethods {
127+
fn m(&mut self, x: i32) -> i32 { x + 1 }
128+
fn i(&self, x: i32) -> i32 { x + 1 }
129+
}
130+
131+
struct T;
132+
133+
impl TwoMethods for T { }
134+
135+
struct S;
136+
137+
impl S {
138+
fn m(&mut self, x: i32) -> i32 { x + 1 }
139+
fn i(&self, x: i32) -> i32 { x + 1 }
140+
}
141+
142+
impl TwoMethods for [i32; 3] { }
143+
144+
fn double_access<X: Copy>(m: &mut [X], s: &[X]) {
145+
m[0] = s[1];
34146
}
35147

36-
#[rustc_error]
37-
fn main() { //[g2p]~ ERROR compilation successful
38-
bar(&mut 5);
148+
fn coerce_unsized() {
149+
let mut a = [1, 2, 3];
150+
151+
// This is not okay.
152+
double_access(&mut a, &a);
153+
//[lxl]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
154+
//[nll]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
155+
//[g2p]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
156+
157+
// But this is okay.
158+
a.m(a.i(10));
159+
}
160+
161+
struct I(i32);
162+
163+
impl Index<i32> for I {
164+
type Output = i32;
165+
fn index(&self, _: i32) -> &i32 {
166+
&self.0
167+
}
168+
}
169+
170+
impl IndexMut<i32> for I {
171+
fn index_mut(&mut self, _: i32) -> &mut i32 {
172+
&mut self.0
173+
}
174+
}
175+
176+
fn coerce_index_op() {
177+
let mut i = I(10);
178+
i[i[3]] = 4;
179+
//[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
180+
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
181+
182+
i[3] = i[4];
183+
184+
i[i[3]] = i[4];
185+
//[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
186+
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
187+
}
188+
189+
struct A(i32);
190+
191+
macro_rules! trivial_binop {
192+
($Trait:ident, $m:ident) => {
193+
impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
194+
}
195+
}
196+
197+
trivial_binop!(AddAssign, add_assign);
198+
trivial_binop!(SubAssign, sub_assign);
199+
trivial_binop!(MulAssign, mul_assign);
200+
trivial_binop!(DivAssign, div_assign);
201+
trivial_binop!(RemAssign, rem_assign);
202+
trivial_binop!(BitAndAssign, bitand_assign);
203+
trivial_binop!(BitOrAssign, bitor_assign);
204+
trivial_binop!(BitXorAssign, bitxor_assign);
205+
trivial_binop!(ShlAssign, shl_assign);
206+
trivial_binop!(ShrAssign, shr_assign);
207+
208+
fn overloaded_binops() {
209+
let mut a = A(10);
210+
a += a.0;
211+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
212+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
213+
a -= a.0;
214+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
215+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
216+
a *= a.0;
217+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
218+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
219+
a /= a.0;
220+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
221+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
222+
a &= a.0;
223+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
224+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
225+
a |= a.0;
226+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
227+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
228+
a ^= a.0;
229+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
230+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
231+
a <<= a.0;
232+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
233+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
234+
a >>= a.0;
235+
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
236+
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
237+
}
238+
239+
fn main() {
240+
241+
// As a reminder, this is the basic case we want to ensure we handle.
242+
let mut v = vec![1, 2, 3];
243+
v.push(v.len());
244+
245+
// (as a rule, pnkfelix does not like to write tests with dead code.)
246+
247+
deref_coercion(&mut 5);
248+
overloaded_call_traits();
249+
250+
251+
let mut s = S;
252+
s.m(s.i(10));
253+
254+
let mut t = T;
255+
t.m(t.i(10));
256+
257+
coerce_unsized();
258+
coerce_index_op();
259+
overloaded_binops();
39260
}

0 commit comments

Comments
 (0)