Skip to content

Commit

Permalink
Tests illustrating the bug fixes for #27282 and #24535.
Browse files Browse the repository at this point in the history
  • Loading branch information
pnkfelix committed May 29, 2018
1 parent 5eebd36 commit 98d5e13
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 0 deletions.
@@ -0,0 +1,68 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This test illustrates that under NLL, we can remove our overly
// conservative approach for disallowing mutations of match inputs.

// See further discussion on rust-lang/rust#24535 and
// rust-lang/rfcs#1006.

// compile-flags: -Z disable-ast-check-for-mutation-in-guard

#![feature(nll)]

fn main() {
rust_issue_24535();
rfcs_issue_1006_1();
rfcs_issue_1006_2();
}

fn rust_issue_24535() {
fn compare(a: &u8, b: &mut u8) -> bool {
a == b
}

let a = 3u8;

match a {
0 => panic!("nope"),
3 if compare(&a, &mut 3) => (),
_ => panic!("nope"),
}
}

fn rfcs_issue_1006_1() {
let v = vec!["1".to_string(), "2".to_string(), "3".to_string()];
match Some(&v) {
Some(iv) if iv.iter().any(|x| &x[..]=="2") => true,
_ => panic!("nope"),
};
}

fn rfcs_issue_1006_2() {
#[inline(always)]
fn check<'a, I: Iterator<Item=&'a i32>>(mut i: I) -> bool {
i.any(|&x| x == 2)
}

let slice = [1, 2, 3];

match 42 {
_ if slice.iter().any(|&x| x == 2) => { true },
_ => { panic!("nope"); }
};

// (This match is just illustrating how easy it was to circumvent
// the checking performed for the previous `match`.)
match 42 {
_ if check(slice.iter()) => { true },
_ => { panic!("nope"); }
};
}
33 changes: 33 additions & 0 deletions src/test/ui/issue-27282-move-match-input-into-guard.rs
@@ -0,0 +1,33 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Issue 27282: Example 2: This sidesteps the AST checks disallowing
// mutable borrows in match guards by hiding the mutable borrow in a
// guard behind a move (of the mutably borrowed match input) within a
// closure.
//
// This example is not rejected by AST borrowck (and then reliably
// reaches the panic code when executed, despite the compiler warning
// about that match arm being unreachable.

#![feature(nll)]

fn main() {
let b = &mut true;
match b {
&mut false => {},
_ if { (|| { let bar = b; *bar = false; })();
//~^ ERROR cannot move out of `b` because it is borrowed [E0505]
false } => { },
&mut true => { println!("You might think we should get here"); },
//~^ ERROR use of moved value: `*b` [E0382]
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}
}
32 changes: 32 additions & 0 deletions src/test/ui/issue-27282-move-match-input-into-guard.stderr
@@ -0,0 +1,32 @@
error[E0505]: cannot move out of `b` because it is borrowed
--> $DIR/issue-27282-move-match-input-into-guard.rs:26:16
|
LL | match b {
| _____-
| |_____|
| ||
LL | || &mut false => {},
LL | || _ if { (|| { let bar = b; *bar = false; })();
| || ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `b` occurs here
LL | || //~^ ERROR cannot move out of `b` because it is borrowed [E0505]
... ||
LL | || _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
LL | || }
| || -
| ||_____|
| |______borrow of `b` occurs here
| borrow later used here

error[E0382]: use of moved value: `*b`
--> $DIR/issue-27282-move-match-input-into-guard.rs:29:14
|
LL | _ if { (|| { let bar = b; *bar = false; })();
| ----------------------------------- value moved here
...
LL | &mut true => { println!("You might think we should get here"); },
| ^^^^ value used here after move

error: aborting due to 2 previous errors

Some errors occurred: E0382, E0505.
For more information about an error, try `rustc --explain E0382`.
28 changes: 28 additions & 0 deletions src/test/ui/issue-27282-move-ref-mut-into-guard.rs
@@ -0,0 +1,28 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Issue 27282: Example 1: This sidesteps the AST checks disallowing
// mutable borrows in match guards by hiding the mutable borrow in a
// guard behind a move (of the ref mut pattern id) within a closure.
//
// This example is not rejected by AST borrowck (and then reliably
// segfaults when executed).

#![feature(nll)]

fn main() {
match Some(&4) {
None => {},
ref mut foo
if { (|| { let bar = foo; bar.take() })(); false } => {},
//~^ ERROR cannot move out of borrowed content [E0507]
Some(s) => std::process::exit(*s),
}
}
9 changes: 9 additions & 0 deletions src/test/ui/issue-27282-move-ref-mut-into-guard.stderr
@@ -0,0 +1,9 @@
error[E0507]: cannot move out of borrowed content
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:24:18
|
LL | if { (|| { let bar = foo; bar.take() })(); false } => {},
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content

error: aborting due to previous error

For more information about this error, try `rustc --explain E0507`.
32 changes: 32 additions & 0 deletions src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs
@@ -0,0 +1,32 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Issue 27282: This is a variation on issue-27282-move-ref-mut-into-guard.rs
//
// It reborrows instead of moving the `ref mut` pattern borrow. This
// means that our conservative check for mutation in guards will
// reject it. But I want to make sure that we continue to reject it
// (under NLL) even when that conservaive check goes away.

// compile-flags: -Z disable-ast-check-for-mutation-in-guard

#![feature(nll)]

fn main() {
let mut b = &mut true;
match b {
&mut false => {},
ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
//~^ ERROR cannot borrow immutable item `*r` as mutable
false } => { &mut *r; },
&mut true => { println!("You might think we should get here"); },
_ => panic!("surely we could never get here, since rustc warns it is unreachable."),
}
}
9 changes: 9 additions & 0 deletions src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr
@@ -0,0 +1,9 @@
error[E0596]: cannot borrow immutable item `*r` as mutable
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:26:24
|
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0596`.

0 comments on commit 98d5e13

Please sign in to comment.