about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-09-13 22:04:00 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2018-09-24 23:33:13 +0100
commitc5047cb4944297566d236a663bbbba00f2f25cd0 (patch)
tree062417d6930738f22325b53131878b1b09f8d2b2
parent46e247bcec13f3e1e850c3baffc23e64a8023ae4 (diff)
downloadrust-c5047cb4944297566d236a663bbbba00f2f25cd0.tar.gz
rust-c5047cb4944297566d236a663bbbba00f2f25cd0.zip
Add tests for new match borrows
-rw-r--r--src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs30
-rw-r--r--src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr14
-rw-r--r--src/test/ui/nll/match-guards-partially-borrow.rs164
-rw-r--r--src/test/ui/nll/match-guards-partially-borrow.stderr132
-rw-r--r--src/test/ui/nll/match-on-borrowed.rs95
-rw-r--r--src/test/ui/nll/match-on-borrowed.stderr22
6 files changed, 457 insertions, 0 deletions
diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs
new file mode 100644
index 00000000000..4cf5bcd6b4f
--- /dev/null
+++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs
@@ -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"),
+    }
+}
diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr
new file mode 100644
index 00000000000..f46a42d7508
--- /dev/null
+++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr
@@ -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`.
diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs
new file mode 100644
index 00000000000..49846f620f0
--- /dev/null
+++ b/src/test/ui/nll/match-guards-partially-borrow.rs
@@ -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() {}
diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr
new file mode 100644
index 00000000000..2cbfeb886b5
--- /dev/null
+++ b/src/test/ui/nll/match-guards-partially-borrow.stderr
@@ -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`.
diff --git a/src/test/ui/nll/match-on-borrowed.rs b/src/test/ui/nll/match-on-borrowed.rs
new file mode 100644
index 00000000000..6a8ce03e8fd
--- /dev/null
+++ b/src/test/ui/nll/match-on-borrowed.rs
@@ -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() {}
diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr
new file mode 100644
index 00000000000..cdff29d44b8
--- /dev/null
+++ b/src/test/ui/nll/match-on-borrowed.stderr
@@ -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`.