diff --git a/src/test/run-pass/issue-24535-allow-mutable-borrow-in-match-guard.rs b/src/test/run-pass/issue-24535-allow-mutable-borrow-in-match-guard.rs new file mode 100644 index 0000000000000..ac415e31f2b64 --- /dev/null +++ b/src/test/run-pass/issue-24535-allow-mutable-borrow-in-match-guard.rs @@ -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 or the MIT license +// , 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>(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"); } + }; +} diff --git a/src/test/ui/issue-27282-move-match-input-into-guard.rs b/src/test/ui/issue-27282-move-match-input-into-guard.rs new file mode 100644 index 0000000000000..b3be36e41e657 --- /dev/null +++ b/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 or the MIT license +// , 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."), + } +} diff --git a/src/test/ui/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/issue-27282-move-match-input-into-guard.stderr new file mode 100644 index 0000000000000..f89388f1738ea --- /dev/null +++ b/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`. diff --git a/src/test/ui/issue-27282-move-ref-mut-into-guard.rs b/src/test/ui/issue-27282-move-ref-mut-into-guard.rs new file mode 100644 index 0000000000000..5b4c746a1b611 --- /dev/null +++ b/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 or the MIT license +// , 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), + } +} diff --git a/src/test/ui/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/issue-27282-move-ref-mut-into-guard.stderr new file mode 100644 index 0000000000000..f6ffa90069cc4 --- /dev/null +++ b/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`. diff --git a/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.rs new file mode 100644 index 0000000000000..5d445c63ef492 --- /dev/null +++ b/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 or the MIT license +// , 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."), + } +} diff --git a/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/issue-27282-reborrow-ref-mut-in-guard.stderr new file mode 100644 index 0000000000000..d767fdde9f217 --- /dev/null +++ b/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`.