Add tests for new match borrows

This commit is contained in:
Matthew Jasper 2018-09-13 22:04:00 +01:00
parent 46e247bcec
commit c5047cb494
6 changed files with 457 additions and 0 deletions

View file

@ -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"),
}
}

View file

@ -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`.

View 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() {}

View 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`.

View 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() {}

View 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`.