]> git.lizzy.rs Git - rust.git/blob - src/test/ui/borrowck/two-phase-nonrecv-autoref.rs
30752e8ddb1086018331e639f246697998710027
[rust.git] / src / test / ui / borrowck / two-phase-nonrecv-autoref.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // revisions: ast nll
12 //[ast]compile-flags:
13 //[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows
14
15 //[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
16 // the above revision is disabled until two-phase-beyond-autoref support is better
17
18 // This is a test checking that when we limit two-phase borrows to
19 // method receivers, we do not let other kinds of auto-ref to leak
20 // through.
21 //
22 // The g2p revision illustrates the "undesirable" behavior you would
23 // otherwise observe without limiting the phasing to autoref on method
24 // receivers (namely, in many cases demonstrated below, the error
25 // would not arise).
26
27 // (If we revise the compiler or this test so that the g2p revision
28 // passes, turn the `rustc_attrs` feature back on and tag the `fn
29 // main` with `#[rustc_error]` so that this remains a valid
30 // compile-fail test.)
31 //
32 // #![feature(rustc_attrs)]
33
34 use std::ops::{Index, IndexMut};
35
36 fn foo(x: &mut u32, y: u32) {
37     *x += y;
38 }
39
40 fn deref_coercion(x: &mut u32) {
41     foo(x, *x);
42     //[ast]~^ ERROR cannot use `*x` because it was mutably borrowed [E0503]
43     // Above error is a known limitation of AST borrowck
44 }
45
46 // While adding a flag to adjustments (indicating whether they
47 // should support two-phase borrows, here are the cases I
48 // encountered:
49 //
50 // - [x] Resolving overloaded_call_traits (call, call_mut, call_once)
51 // - [x] deref_coercion (shown above)
52 // - [x] coerce_unsized e.g. `&[T; n]`, `&mut [T; n] -> &[T]`,
53 //                      `&mut [T; n] -> &mut [T]`, `&Concrete -> &Trait`
54 // - [x] Method Call Receivers (the case we want to support!)
55 // - [x] ExprKind::Index and ExprKind::Unary Deref; only need to handle coerce_index_op
56 // - [x] overloaded_binops
57
58 fn overloaded_call_traits() {
59     // Regarding overloaded call traits, note that there is no
60     // scenario where adding two-phase borrows should "fix" these
61     // cases, because either we will resolve both invocations to
62     // `call_mut` (in which case the inner call requires a mutable
63     // borrow which will conflict with the outer reservation), or we
64     // will resolve both to `call` (which will just work, regardless
65     // of two-phase borrow support), or we will resolve both to
66     // `call_once` (in which case the inner call requires moving the
67     // receiver, invalidating the outer call).
68
69     fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
70         f(f(10));
71         //[nll]~^   ERROR cannot borrow `*f` as mutable more than once at a time
72         //[g2p]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
73         //[ast]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
74     }
75     fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
76         f(f(10));
77     }
78     fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
79         f(f(10));
80         //[nll]~^   ERROR use of moved value: `*f`
81         //[g2p]~^^  ERROR use of moved value: `*f`
82         //[ast]~^^^ ERROR use of moved value: `*f`
83     }
84
85     fn twice_ten_om(f: &mut FnMut(i32) -> i32) {
86         f(f(10));
87         //[nll]~^   ERROR cannot borrow `*f` as mutable more than once at a time
88         //[g2p]~^^  ERROR cannot borrow `*f` as mutable more than once at a time
89         //[ast]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
90     }
91     fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
92         f(f(10));
93     }
94     fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) {
95         f(f(10));
96         //[nll]~^          ERROR cannot move a value of type
97         //[nll]~^^         ERROR cannot move a value of type
98         //[nll]~^^^        ERROR use of moved value: `*f`
99         //[g2p]~^^^^       ERROR cannot move a value of type
100         //[g2p]~^^^^^      ERROR cannot move a value of type
101         //[g2p]~^^^^^^     ERROR use of moved value: `*f`
102         //[ast]~^^^^^^^    ERROR use of moved value: `*f`
103     }
104
105     twice_ten_sm(&mut |x| x + 1);
106     twice_ten_si(&mut |x| x + 1);
107     twice_ten_so(Box::new(|x| x + 1));
108     twice_ten_om(&mut |x| x + 1);
109     twice_ten_oi(&mut |x| x + 1);
110     twice_ten_oo(Box::new(|x| x + 1));
111 }
112
113 trait TwoMethods {
114     fn m(&mut self, x: i32) -> i32 { x + 1 }
115     fn i(&self, x: i32) -> i32 { x + 1 }
116 }
117
118 struct T;
119
120 impl TwoMethods for T { }
121
122 struct S;
123
124 impl S {
125     fn m(&mut self, x: i32) -> i32 { x + 1 }
126     fn i(&self, x: i32) -> i32 { x + 1 }
127 }
128
129 impl TwoMethods for [i32; 3] { }
130
131 fn double_access<X: Copy>(m: &mut [X], s: &[X]) {
132     m[0] = s[1];
133 }
134
135 fn coerce_unsized() {
136     let mut a = [1, 2, 3];
137
138     // This is not okay.
139     double_access(&mut a, &a);
140     //[nll]~^   ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
141     //[g2p]~^^  ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
142     //[ast]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
143
144     // But this is okay.
145     a.m(a.i(10));
146     //[ast]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
147     // Above error is an expected limitation of AST borrowck
148 }
149
150 struct I(i32);
151
152 impl Index<i32> for I {
153     type Output = i32;
154     fn index(&self, _: i32) -> &i32 {
155         &self.0
156     }
157 }
158
159 impl IndexMut<i32> for I {
160     fn index_mut(&mut self, _: i32) -> &mut i32 {
161         &mut self.0
162     }
163 }
164
165 fn coerce_index_op() {
166     let mut i = I(10);
167     i[i[3]] = 4;
168     //[nll]~^  ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
169     //[ast]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
170
171     i[3] = i[4];
172
173     i[i[3]] = i[4];
174     //[nll]~^  ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
175     //[ast]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
176 }
177
178 fn main() {
179
180     // As a reminder, this is the basic case we want to ensure we handle.
181     let mut v = vec![1, 2, 3];
182     v.push(v.len());
183     //[ast]~^ ERROR cannot borrow `v` as immutable because it is also borrowed as mutable [E0502]
184     // Error above is an expected limitation of AST borrowck
185
186     // (as a rule, pnkfelix does not like to write tests with dead code.)
187
188     deref_coercion(&mut 5);
189     overloaded_call_traits();
190
191
192     let mut s = S;
193     s.m(s.i(10));
194     //[ast]~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable [E0502]
195     // Error above is an expected limitation of AST borrowck
196
197     let mut t = T;
198     t.m(t.i(10));
199     //[ast]~^ ERROR cannot borrow `t` as immutable because it is also borrowed as mutable [E0502]
200     // Error above is an expected limitation of AST borrowck
201
202     coerce_unsized();
203     coerce_index_op();
204 }