Add tests for new match borrows
This commit is contained in:
parent
46e247bcec
commit
c5047cb494
6 changed files with 457 additions and 0 deletions
|
@ -0,0 +1,30 @@
|
|||
// This is testing an attempt to corrupt the discriminant of the match
|
||||
// arm in a guard, followed by an attempt to continue matching on that
|
||||
// corrupted discriminant in the remaining match arms.
|
||||
//
|
||||
// Basically this is testing that our new NLL feature of emitting a
|
||||
// fake read on each match arm is catching cases like this.
|
||||
//
|
||||
// This case is interesting because a borrow of **x is untracked, because **x is
|
||||
// immutable. However, for matches we care that **x refers to the same value
|
||||
// until we have chosen a match arm.
|
||||
#![feature(nll)]
|
||||
struct ForceFnOnce;
|
||||
fn main() {
|
||||
let mut x = &mut &Some(&2);
|
||||
let force_fn_once = ForceFnOnce;
|
||||
match **x {
|
||||
None => panic!("unreachable"),
|
||||
Some(&_) if {
|
||||
// ForceFnOnce needed to exploit #27282
|
||||
(|| { *x = &None; drop(force_fn_once); })();
|
||||
//~^ ERROR cannot mutably borrow `x` in match guard [E0510]
|
||||
false
|
||||
} => {}
|
||||
Some(&a) if { // this binds to garbage if we've corrupted discriminant
|
||||
println!("{}", a);
|
||||
panic!()
|
||||
} => {}
|
||||
_ => panic!("unreachable"),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
error[E0510]: cannot mutably borrow `x` in match guard
|
||||
--> $DIR/issue-27282-mutate-before-diverging-arm-3.rs:20:14
|
||||
|
|
||||
LL | match **x {
|
||||
| --- value is immutable in match guard
|
||||
...
|
||||
LL | (|| { *x = &None; drop(force_fn_once); })();
|
||||
| ^^ - borrow occurs due to use of `x` in closure
|
||||
| |
|
||||
| cannot mutably borrow
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0510`.
|
164
src/test/ui/nll/match-guards-partially-borrow.rs
Normal file
164
src/test/ui/nll/match-guards-partially-borrow.rs
Normal file
|
@ -0,0 +1,164 @@
|
|||
// Test that a (partially) mutably borrowed place can be matched on, so long as
|
||||
// we don't have to read any values that are mutably borrowed to determine
|
||||
// which arm to take.
|
||||
//
|
||||
// Test that we don't allow mutating the value being matched on in a way that
|
||||
// changes which patterns it matches, until we have chosen an arm.
|
||||
|
||||
// compile-flags: -Zdisable-ast-check-for-mutation-in-guard
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
fn ok_mutation_in_guard(mut q: i32) {
|
||||
match q {
|
||||
// OK, mutation doesn't change which patterns g matches
|
||||
_ if { q = 1; false } => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn ok_indirect_mutation_in_guard(mut p: &bool) {
|
||||
match *p {
|
||||
// OK, mutation doesn't change which patterns s matches
|
||||
_ if {
|
||||
p = &true;
|
||||
false
|
||||
} => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn mutation_invalidates_pattern_in_guard(mut q: bool) {
|
||||
match q {
|
||||
// s doesn't match the pattern with the guard by the end of the guard.
|
||||
false if {
|
||||
q = true; //~ ERROR
|
||||
true
|
||||
} => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
|
||||
match r {
|
||||
// s matches a previous pattern by the end of the guard.
|
||||
true => (),
|
||||
_ if {
|
||||
r = true; //~ ERROR
|
||||
true
|
||||
} => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn match_on_borrowed_early_end(mut s: bool) {
|
||||
let h = &mut s;
|
||||
match s { //~ ERROR
|
||||
// s changes value between the start of the match and when its value is checked.
|
||||
_ if {
|
||||
*h = !*h;
|
||||
false
|
||||
} => (),
|
||||
true => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_mutation_in_guard(mut t: bool) {
|
||||
match t {
|
||||
true => (),
|
||||
false if {
|
||||
t = true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_mutation_in_guard2(mut u: bool) {
|
||||
match u {
|
||||
// Guard changes the value bound in the last pattern.
|
||||
_ => (),
|
||||
_ if {
|
||||
u = true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
x => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bad_mutation_in_guard3(mut x: Option<Option<&i32>>) {
|
||||
// Check that nested patterns are checked.
|
||||
match x {
|
||||
None => (),
|
||||
Some(None) => (),
|
||||
_ if {
|
||||
match x {
|
||||
Some(ref mut r) => *r = None, //~ ERROR
|
||||
_ => return,
|
||||
};
|
||||
false
|
||||
} => (),
|
||||
Some(Some(r)) => println!("{}", r),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn bad_mutation_in_guard4(mut w: (&mut bool,)) {
|
||||
match w {
|
||||
// Guard changes the value bound in the last pattern.
|
||||
_ => (),
|
||||
_ if {
|
||||
*w.0 = true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
x => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard(mut y: &bool) {
|
||||
match *y {
|
||||
true => (),
|
||||
false if {
|
||||
y = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard2(mut z: &bool) {
|
||||
match z {
|
||||
&true => (),
|
||||
&false if {
|
||||
z = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
&false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard3(mut a: &bool) {
|
||||
// Same as bad_indirect_mutation_in_guard2, but using match ergonomics
|
||||
match a {
|
||||
true => (),
|
||||
false if {
|
||||
a = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard4(mut b: &bool) {
|
||||
match b {
|
||||
&_ => (),
|
||||
&_ if {
|
||||
b = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
&b => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
132
src/test/ui/nll/match-guards-partially-borrow.stderr
Normal file
132
src/test/ui/nll/match-guards-partially-borrow.stderr
Normal file
|
@ -0,0 +1,132 @@
|
|||
error[E0510]: cannot assign `q` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:35:13
|
||||
|
|
||||
LL | match q {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | q = true; //~ ERROR
|
||||
| ^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | _ => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `r` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:47:13
|
||||
|
|
||||
LL | match r {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | r = true; //~ ERROR
|
||||
| ^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | _ => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `s` because it was mutably borrowed
|
||||
--> $DIR/match-guards-partially-borrow.rs:56:11
|
||||
|
|
||||
LL | let h = &mut s;
|
||||
| ------ borrow of `s` occurs here
|
||||
LL | match s { //~ ERROR
|
||||
| ^ use of borrowed `s`
|
||||
...
|
||||
LL | *h = !*h;
|
||||
| -- borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `t` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:71:13
|
||||
|
|
||||
LL | match t {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | t = true; //~ ERROR
|
||||
| ^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | false => (),
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0506]: cannot assign to `u` because it is borrowed
|
||||
--> $DIR/match-guards-partially-borrow.rs:83:13
|
||||
|
|
||||
LL | match u {
|
||||
| - borrow of `u` occurs here
|
||||
...
|
||||
LL | u = true; //~ ERROR
|
||||
| ^^^^^^^^ assignment to borrowed `u` occurs here
|
||||
...
|
||||
LL | x => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0510]: cannot mutably borrow `x.0` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:97:22
|
||||
|
|
||||
LL | match x {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | Some(ref mut r) => *r = None, //~ ERROR
|
||||
| ^^^^^^^^^ cannot mutably borrow
|
||||
|
||||
error[E0506]: cannot assign to `*w.0` because it is borrowed
|
||||
--> $DIR/match-guards-partially-borrow.rs:112:13
|
||||
|
|
||||
LL | match w {
|
||||
| - borrow of `*w.0` occurs here
|
||||
...
|
||||
LL | *w.0 = true; //~ ERROR
|
||||
| ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here
|
||||
...
|
||||
LL | x => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `y` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:123:13
|
||||
|
|
||||
LL | match *y {
|
||||
| -- value is immutable in match guard
|
||||
...
|
||||
LL | y = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | false => (),
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `z` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:134:13
|
||||
|
|
||||
LL | match z {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | z = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | &false => (),
|
||||
| ------ borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `a` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:146:13
|
||||
|
|
||||
LL | match a {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | a = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | false => (),
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `b` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:157:13
|
||||
|
|
||||
LL | match b {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | b = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | &b => (),
|
||||
| -- borrow later used here
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors occurred: E0503, E0506, E0510.
|
||||
For more information about an error, try `rustc --explain E0503`.
|
95
src/test/ui/nll/match-on-borrowed.rs
Normal file
95
src/test/ui/nll/match-on-borrowed.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Test that a (partially) mutably borrowed place can be matched on, so long as
|
||||
// we don't have to read any values that are mutably borrowed to determine
|
||||
// which arm to take.
|
||||
//
|
||||
// Test that we don't allow mutating the value being matched on in a way that
|
||||
// changes which patterns it matches, until we have chosen an arm.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
struct A(i32, i32);
|
||||
|
||||
fn struct_example(mut a: A) {
|
||||
let x = &mut a.0;
|
||||
match a { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
A(_, r) => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn indirect_struct_example(mut b: &mut A) {
|
||||
let x = &mut b.0;
|
||||
match *b { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
A(_, r) => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn underscore_example(mut c: i32) {
|
||||
let r = &mut c;
|
||||
match c { // OK, no access of borrowed data (or any data at all)
|
||||
_ if false => (),
|
||||
_ => (),
|
||||
}
|
||||
r;
|
||||
}
|
||||
|
||||
enum E {
|
||||
V(i32, i32),
|
||||
W,
|
||||
}
|
||||
|
||||
fn enum_example(mut e: E) {
|
||||
let x = match e {
|
||||
E::V(ref mut x, _) => x,
|
||||
E::W => panic!(),
|
||||
};
|
||||
match e { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
E::V(_, r) => (),
|
||||
E::W => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn indirect_enum_example(mut f: &mut E) {
|
||||
let x = match *f {
|
||||
E::V(ref mut x, _) => x,
|
||||
E::W => panic!(),
|
||||
};
|
||||
match f { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
E::V(_, r) => (),
|
||||
E::W => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn match_on_muatbly_borrowed_ref(mut p: &bool) {
|
||||
let r = &mut p;
|
||||
match *p { // OK, no access at all
|
||||
_ if false => (),
|
||||
_ => (),
|
||||
}
|
||||
r;
|
||||
}
|
||||
|
||||
fn match_on_borrowed(mut t: bool) {
|
||||
let x = &mut t;
|
||||
match t {
|
||||
true => (), //~ ERROR
|
||||
false => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
enum Never {}
|
||||
|
||||
fn never_init() {
|
||||
let n: Never;
|
||||
match n {} //~ ERROR
|
||||
}
|
||||
|
||||
fn main() {}
|
22
src/test/ui/nll/match-on-borrowed.stderr
Normal file
22
src/test/ui/nll/match-on-borrowed.stderr
Normal file
|
@ -0,0 +1,22 @@
|
|||
error[E0503]: cannot use `t` because it was mutably borrowed
|
||||
--> $DIR/match-on-borrowed.rs:82:9
|
||||
|
|
||||
LL | let x = &mut t;
|
||||
| ------ borrow of `t` occurs here
|
||||
LL | match t {
|
||||
LL | true => (), //~ ERROR
|
||||
| ^^^^ use of borrowed `t`
|
||||
...
|
||||
LL | x;
|
||||
| - borrow later used here
|
||||
|
||||
error[E0381]: use of possibly uninitialized variable: `n`
|
||||
--> $DIR/match-on-borrowed.rs:92:11
|
||||
|
|
||||
LL | match n {} //~ ERROR
|
||||
| ^ use of possibly uninitialized `n`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors occurred: E0381, E0503.
|
||||
For more information about an error, try `rustc --explain E0381`.
|
Loading…
Add table
Reference in a new issue