Skip to content

Commit fce7645

Browse files
committed
Add tests for new match borrows
1 parent 441ee5c commit fce7645

6 files changed

+457
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This is testing an attempt to corrupt the discriminant of the match
2+
// arm in a guard, followed by an attempt to continue matching on that
3+
// corrupted discriminant in the remaining match arms.
4+
//
5+
// Basically this is testing that our new NLL feature of emitting a
6+
// fake read on each match arm is catching cases like this.
7+
//
8+
// This case is interesting because a borrow of **x is untracked, because **x is
9+
// immutable. However, for matches we care that **x refers to the same value
10+
// until we have chosen a match arm.
11+
#![feature(nll)]
12+
struct ForceFnOnce;
13+
fn main() {
14+
let mut x = &mut &Some(&2);
15+
let force_fn_once = ForceFnOnce;
16+
match **x {
17+
None => panic!("unreachable"),
18+
Some(&_) if {
19+
// ForceFnOnce needed to exploit #27282
20+
(|| { *x = &None; drop(force_fn_once); })();
21+
//~^ ERROR cannot mutably borrow `x` in match guard [E0510]
22+
false
23+
} => {}
24+
Some(&a) if { // this binds to garbage if we've corrupted discriminant
25+
println!("{}", a);
26+
panic!()
27+
} => {}
28+
_ => panic!("unreachable"),
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0510]: cannot mutably borrow `x` in match guard
2+
--> $DIR/issue-27282-mutate-before-diverging-arm-3.rs:20:14
3+
|
4+
LL | match **x {
5+
| --- value is immutable in match guard
6+
...
7+
LL | (|| { *x = &None; drop(force_fn_once); })();
8+
| ^^ - borrow occurs due to use of `x` in closure
9+
| |
10+
| cannot mutably borrow
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0510`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Test that a (partially) mutably borrowed place can be matched on, so long as
2+
// we don't have to read any values that are mutably borrowed to determine
3+
// which arm to take.
4+
//
5+
// Test that we don't allow mutating the value being matched on in a way that
6+
// changes which patterns it matches, until we have chosen an arm.
7+
8+
// compile-flags: -Zdisable-ast-check-for-mutation-in-guard
9+
10+
#![feature(nll)]
11+
12+
fn ok_mutation_in_guard(mut q: i32) {
13+
match q {
14+
// OK, mutation doesn't change which patterns g matches
15+
_ if { q = 1; false } => (),
16+
_ => (),
17+
}
18+
}
19+
20+
fn ok_indirect_mutation_in_guard(mut p: &bool) {
21+
match *p {
22+
// OK, mutation doesn't change which patterns s matches
23+
_ if {
24+
p = &true;
25+
false
26+
} => (),
27+
_ => (),
28+
}
29+
}
30+
31+
fn mutation_invalidates_pattern_in_guard(mut q: bool) {
32+
match q {
33+
// s doesn't match the pattern with the guard by the end of the guard.
34+
false if {
35+
q = true; //~ ERROR
36+
true
37+
} => (),
38+
_ => (),
39+
}
40+
}
41+
42+
fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
43+
match r {
44+
// s matches a previous pattern by the end of the guard.
45+
true => (),
46+
_ if {
47+
r = true; //~ ERROR
48+
true
49+
} => (),
50+
_ => (),
51+
}
52+
}
53+
54+
fn match_on_borrowed_early_end(mut s: bool) {
55+
let h = &mut s;
56+
match s { //~ ERROR
57+
// s changes value between the start of the match and when its value is checked.
58+
_ if {
59+
*h = !*h;
60+
false
61+
} => (),
62+
true => (),
63+
false => (),
64+
}
65+
}
66+
67+
fn bad_mutation_in_guard(mut t: bool) {
68+
match t {
69+
true => (),
70+
false if {
71+
t = true; //~ ERROR
72+
false
73+
} => (),
74+
false => (),
75+
}
76+
}
77+
78+
fn bad_mutation_in_guard2(mut u: bool) {
79+
match u {
80+
// Guard changes the value bound in the last pattern.
81+
_ => (),
82+
_ if {
83+
u = true; //~ ERROR
84+
false
85+
} => (),
86+
x => (),
87+
}
88+
}
89+
90+
pub fn bad_mutation_in_guard3(mut x: Option<Option<&i32>>) {
91+
// Check that nested patterns are checked.
92+
match x {
93+
None => (),
94+
Some(None) => (),
95+
_ if {
96+
match x {
97+
Some(ref mut r) => *r = None, //~ ERROR
98+
_ => return,
99+
};
100+
false
101+
} => (),
102+
Some(Some(r)) => println!("{}", r),
103+
}
104+
}
105+
106+
107+
fn bad_mutation_in_guard4(mut w: (&mut bool,)) {
108+
match w {
109+
// Guard changes the value bound in the last pattern.
110+
_ => (),
111+
_ if {
112+
*w.0 = true; //~ ERROR
113+
false
114+
} => (),
115+
x => (),
116+
}
117+
}
118+
119+
fn bad_indirect_mutation_in_guard(mut y: &bool) {
120+
match *y {
121+
true => (),
122+
false if {
123+
y = &true; //~ ERROR
124+
false
125+
} => (),
126+
false => (),
127+
}
128+
}
129+
130+
fn bad_indirect_mutation_in_guard2(mut z: &bool) {
131+
match z {
132+
&true => (),
133+
&false if {
134+
z = &true; //~ ERROR
135+
false
136+
} => (),
137+
&false => (),
138+
}
139+
}
140+
141+
fn bad_indirect_mutation_in_guard3(mut a: &bool) {
142+
// Same as bad_indirect_mutation_in_guard2, but using match ergonomics
143+
match a {
144+
true => (),
145+
false if {
146+
a = &true; //~ ERROR
147+
false
148+
} => (),
149+
false => (),
150+
}
151+
}
152+
153+
fn bad_indirect_mutation_in_guard4(mut b: &bool) {
154+
match b {
155+
&_ => (),
156+
&_ if {
157+
b = &true; //~ ERROR
158+
false
159+
} => (),
160+
&b => (),
161+
}
162+
}
163+
164+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
error[E0510]: cannot assign `q` in match guard
2+
--> $DIR/match-guards-partially-borrow.rs:35:13
3+
|
4+
LL | match q {
5+
| - value is immutable in match guard
6+
...
7+
LL | q = true; //~ ERROR
8+
| ^^^^^^^^ cannot assign
9+
...
10+
LL | _ => (),
11+
| - borrow later used here
12+
13+
error[E0510]: cannot assign `r` in match guard
14+
--> $DIR/match-guards-partially-borrow.rs:47:13
15+
|
16+
LL | match r {
17+
| - value is immutable in match guard
18+
...
19+
LL | r = true; //~ ERROR
20+
| ^^^^^^^^ cannot assign
21+
...
22+
LL | _ => (),
23+
| - borrow later used here
24+
25+
error[E0503]: cannot use `s` because it was mutably borrowed
26+
--> $DIR/match-guards-partially-borrow.rs:56:11
27+
|
28+
LL | let h = &mut s;
29+
| ------ borrow of `s` occurs here
30+
LL | match s { //~ ERROR
31+
| ^ use of borrowed `s`
32+
...
33+
LL | *h = !*h;
34+
| -- borrow later used here
35+
36+
error[E0510]: cannot assign `t` in match guard
37+
--> $DIR/match-guards-partially-borrow.rs:71:13
38+
|
39+
LL | match t {
40+
| - value is immutable in match guard
41+
...
42+
LL | t = true; //~ ERROR
43+
| ^^^^^^^^ cannot assign
44+
...
45+
LL | false => (),
46+
| ----- borrow later used here
47+
48+
error[E0506]: cannot assign to `u` because it is borrowed
49+
--> $DIR/match-guards-partially-borrow.rs:83:13
50+
|
51+
LL | match u {
52+
| - borrow of `u` occurs here
53+
...
54+
LL | u = true; //~ ERROR
55+
| ^^^^^^^^ assignment to borrowed `u` occurs here
56+
...
57+
LL | x => (),
58+
| - borrow later used here
59+
60+
error[E0510]: cannot mutably borrow `x.0` in match guard
61+
--> $DIR/match-guards-partially-borrow.rs:97:22
62+
|
63+
LL | match x {
64+
| - value is immutable in match guard
65+
...
66+
LL | Some(ref mut r) => *r = None, //~ ERROR
67+
| ^^^^^^^^^ cannot mutably borrow
68+
69+
error[E0506]: cannot assign to `*w.0` because it is borrowed
70+
--> $DIR/match-guards-partially-borrow.rs:112:13
71+
|
72+
LL | match w {
73+
| - borrow of `*w.0` occurs here
74+
...
75+
LL | *w.0 = true; //~ ERROR
76+
| ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here
77+
...
78+
LL | x => (),
79+
| - borrow later used here
80+
81+
error[E0510]: cannot assign `y` in match guard
82+
--> $DIR/match-guards-partially-borrow.rs:123:13
83+
|
84+
LL | match *y {
85+
| -- value is immutable in match guard
86+
...
87+
LL | y = &true; //~ ERROR
88+
| ^^^^^^^^^ cannot assign
89+
...
90+
LL | false => (),
91+
| ----- borrow later used here
92+
93+
error[E0510]: cannot assign `z` in match guard
94+
--> $DIR/match-guards-partially-borrow.rs:134:13
95+
|
96+
LL | match z {
97+
| - value is immutable in match guard
98+
...
99+
LL | z = &true; //~ ERROR
100+
| ^^^^^^^^^ cannot assign
101+
...
102+
LL | &false => (),
103+
| ------ borrow later used here
104+
105+
error[E0510]: cannot assign `a` in match guard
106+
--> $DIR/match-guards-partially-borrow.rs:146:13
107+
|
108+
LL | match a {
109+
| - value is immutable in match guard
110+
...
111+
LL | a = &true; //~ ERROR
112+
| ^^^^^^^^^ cannot assign
113+
...
114+
LL | false => (),
115+
| ----- borrow later used here
116+
117+
error[E0510]: cannot assign `b` in match guard
118+
--> $DIR/match-guards-partially-borrow.rs:157:13
119+
|
120+
LL | match b {
121+
| - value is immutable in match guard
122+
...
123+
LL | b = &true; //~ ERROR
124+
| ^^^^^^^^^ cannot assign
125+
...
126+
LL | &b => (),
127+
| -- borrow later used here
128+
129+
error: aborting due to 11 previous errors
130+
131+
Some errors occurred: E0503, E0506, E0510.
132+
For more information about an error, try `rustc --explain E0503`.

0 commit comments

Comments
 (0)