1
Fork 0

Auto merge of #63118 - Centril:stabilize-bind-by-move, r=matthewjasper

Stabilize `bind_by_move_pattern_guards` in Rust 1.39.0

Closes https://github.com/rust-lang/rust/issues/15287.

After stabilizing `#![feature(bind_by_move_pattern_guards)]`, you can now use bind-by-move bindings in patterns and take references to those bindings in `if` guards of `match` expressions. For example, the following now becomes legal:

```rust
fn main() {
    let array: Box<[u8; 4]> = Box::new([1, 2, 3, 4]);

    match array {
        nums
//      ---- `nums` is bound by move.
            if nums.iter().sum::<u8>() == 10
//                 ^------ `.iter()` implicitly takes a reference to `nums`.
        => {
            drop(nums);
//          --------- Legal as `nums` was bound by move and so we have ownership.
        }
        _ => unreachable!(),
    }
}
```

r? @matthewjasper
This commit is contained in:
bors 2019-09-09 12:46:59 +00:00
commit 45859b7ca7
42 changed files with 51 additions and 427 deletions

View file

@ -87,7 +87,7 @@
#![feature(link_llvm_intrinsics)]
#![feature(never_type)]
#![feature(nll)]
#![feature(bind_by_move_pattern_guards)]
#![cfg_attr(boostrap_stdarch_ignore_this, feature(bind_by_move_pattern_guards))]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(on_unimplemented)]

View file

@ -1345,13 +1345,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// any, and then branches to the arm. Returns the block for the case where
/// the guard fails.
///
/// Note: we check earlier that if there is a guard, there cannot be move
/// bindings (unless feature(bind_by_move_pattern_guards) is used). This
/// isn't really important for the self-consistency of this fn, but the
/// reason for it should be clear: after we've done the assignments, if
/// there were move bindings, further tests would be a use-after-move.
/// bind_by_move_pattern_guards avoids this by only moving the binding once
/// the guard has evaluated to true (see below).
/// Note: we do not check earlier that if there is a guard,
/// there cannot be move bindings. We avoid a use-after-move by only
/// moving the binding once the guard has evaluated to true (see below).
fn bind_and_guard_matched_candidate<'pat>(
&mut self,
candidate: Candidate<'pat, 'tcx>,

View file

@ -157,81 +157,6 @@ match x {
See also the error E0303.
"##,
E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:
```compile_fail,E0008
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {}, // use s.
_ => {},
}
```
The variable `s` has type `String`, and its use in the guard is as a variable of
type `String`. The guard code effectively executes in a separate scope to the
body of the arm, so the value would be moved into this anonymous scope and
therefore becomes unavailable in the body of the arm.
The problem above can be solved by using the `ref` keyword.
```
match Some("hi".to_string()) {
Some(ref s) if s.len() == 0 => {},
_ => {},
}
```
Though this example seems innocuous and easy to solve, the problem becomes clear
when it encounters functions which consume the value:
```compile_fail,E0008
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a {
Some(y) if y.consume() > 0 => {}
_ => {}
}
}
```
In this situation, even the `ref` keyword cannot solve it, since borrowed
content cannot be moved. This problem cannot be solved generally. If the value
can be cloned, here is a not-so-specific solution:
```
#[derive(Clone)]
struct A{}
impl A {
fn consume(self) -> usize {
0
}
}
fn main() {
let a = Some(A{});
match a{
Some(ref y) if y.clone().consume() > 0 => {}
_ => {}
}
}
```
If the value will be consumed in the pattern guard, using its clone will not
move its ownership, so the code works.
"##,
E0009: r##"
In a pattern, all values that don't implement the `Copy` trait have to be bound
the same way. The goal here is to avoid binding simultaneously by-move and
@ -475,13 +400,15 @@ for item in xs {
"##,
E0301: r##"
#### Note: this error code is no longer emitted by the compiler.
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:
```compile_fail,E0301
```compile_fail,E0596
match Some(()) {
None => { },
option if option.take().is_none() => {
@ -493,13 +420,15 @@ match Some(()) {
"##,
E0302: r##"
#### Note: this error code is no longer emitted by the compiler.
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:
```compile_fail,E0302
```compile_fail,E0594
match Some(()) {
None => { },
option if { option = None; false } => { },
@ -1989,7 +1918,6 @@ When matching on a variable it cannot be mutated in the match guards, as this
could cause the match to be non-exhaustive:
```compile_fail,E0510
#![feature(bind_by_move_pattern_guards)]
let mut x = Some(0);
match x {
None => (),
@ -2451,6 +2379,7 @@ There are some known bugs that trigger this message.
;
// E0008, // cannot bind by-move into a pattern guard
// E0298, // cannot compare constants
// E0299, // mismatched types between arms
// E0471, // constant evaluation error (in pattern)

View file

@ -5,11 +5,6 @@ use super::_match::WitnessPreference::*;
use super::{Pattern, PatternContext, PatternError, PatternKind};
use rustc::middle::borrowck::SignalledError;
use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization::cmt_;
use rustc::middle::region;
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{InternalSubsts, SubstsRef};
@ -36,9 +31,7 @@ crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) -> SignalledError {
let mut visitor = MatchVisitor {
tcx,
body_owner: def_id,
tables: tcx.body_tables(body_id),
region_scope_tree: &tcx.region_scope_tree(def_id),
param_env: tcx.param_env(def_id),
identity_substs: InternalSubsts::identity_for_item(tcx, def_id),
signalled_error: SignalledError::NoErrorsSeen,
@ -53,11 +46,9 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu
struct MatchVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
body_owner: DefId,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
identity_substs: SubstsRef<'tcx>,
region_scope_tree: &'a region::ScopeTree,
signalled_error: SignalledError,
}
@ -151,11 +142,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
// Second, if there is a guard on each arm, make sure it isn't
// assigning or borrowing anything mutably.
if let Some(ref guard) = arm.guard {
if arm.guard.is_some() {
self.signalled_error = SignalledError::SawSomeError;
if !self.tcx.features().bind_by_move_pattern_guards {
check_for_mutation_in_guard(self, &guard);
}
}
// Third, perform some lints.
@ -582,19 +570,10 @@ fn check_legality_of_move_bindings(
"cannot bind by-move with sub-bindings")
.span_label(p.span, "binds an already bound by-move value by moving it")
.emit();
} else if has_guard {
if !cx.tcx.features().bind_by_move_pattern_guards {
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
"cannot bind by-move into a pattern guard");
err.span_label(p.span, "moves value into pattern guard");
if cx.tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \
crate attributes to enable");
}
err.emit();
} else if !has_guard {
if let Some(_by_ref_span) = by_ref_span {
span_vec.push(p.span);
}
} else if let Some(_by_ref_span) = by_ref_span {
span_vec.push(p.span);
}
};
@ -636,67 +615,6 @@ fn check_legality_of_move_bindings(
}
}
/// Ensures that a pattern guard doesn't borrow by mutable reference or assign.
//
// FIXME: this should be done by borrowck.
fn check_for_mutation_in_guard(cx: &MatchVisitor<'_, '_>, guard: &hir::Guard) {
let mut checker = MutationChecker {
cx,
};
match guard {
hir::Guard::If(expr) =>
ExprUseVisitor::new(&mut checker,
cx.tcx,
cx.body_owner,
cx.param_env,
cx.region_scope_tree,
cx.tables,
None).walk_expr(expr),
};
}
struct MutationChecker<'a, 'tcx> {
cx: &'a MatchVisitor<'a, 'tcx>,
}
impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
fn matched_pat(&mut self, _: &Pat, _: &cmt_<'_>, _: euv::MatchMode) {}
fn consume(&mut self, _: hir::HirId, _: Span, _: &cmt_<'_>, _: ConsumeMode) {}
fn consume_pat(&mut self, _: &Pat, _: &cmt_<'_>, _: ConsumeMode) {}
fn borrow(&mut self,
_: hir::HirId,
span: Span,
_: &cmt_<'_>,
_: ty::Region<'tcx>,
kind:ty:: BorrowKind,
_: LoanCause) {
match kind {
ty::MutBorrow => {
let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301,
"cannot mutably borrow in a pattern guard");
err.span_label(span, "borrowed mutably in pattern guard");
if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \
crate attributes to enable");
}
err.emit();
}
ty::ImmBorrow | ty::UniqueImmBorrow => {}
}
}
fn decl_without_init(&mut self, _: hir::HirId, _: Span) {}
fn mutate(&mut self, _: hir::HirId, span: Span, _: &cmt_<'_>, mode: MutateMode) {
match mode {
MutateMode::JustWrite | MutateMode::WriteAndRead => {
struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
.span_label(span, "assignment in pattern guard")
.emit();
}
MutateMode::Init => {}
}
}
}
/// Forbids bindings in `@` patterns. This is necessary for memory safety,
/// because of the way rvalues are handled in the borrow check. (See issue
/// #14587.)

View file

@ -8,7 +8,7 @@
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(bind_by_move_pattern_guards)]
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
#![recursion_limit="256"]

View file

@ -1,7 +1,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/")]
#![feature(bind_by_move_pattern_guards)]
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
#![feature(rustc_private)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]

View file

@ -238,7 +238,7 @@
#![feature(array_error_internals)]
#![feature(asm)]
#![feature(associated_type_bounds)]
#![feature(bind_by_move_pattern_guards)]
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
#![feature(box_syntax)]
#![feature(c_variadic)]
#![feature(cfg_target_has_atomic)]

View file

@ -241,6 +241,8 @@ declare_features! (
(accepted, underscore_const_names, "1.37.0", Some(54912), None),
/// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions.
(accepted, async_await, "1.39.0", Some(50547), None),
/// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
(accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features

View file

@ -461,9 +461,6 @@ declare_features! (
/// Allows non-builtin attributes in inner attribute position.
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
/// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
(active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
/// Allows `impl Trait` in bindings (`let`, `const`, `static`).
(active, impl_trait_in_bindings, "1.30.0", Some(63065), None),

View file

@ -7,7 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
#![feature(bind_by_move_pattern_guards)]
#![cfg_attr(bootstrap, feature(bind_by_move_pattern_guards))]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(const_transmute)]

View file

@ -8,8 +8,6 @@
// all of the bindings for that scope.
// * No drop flags are used.
#![feature(nll, bind_by_move_pattern_guards)]
fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
match items {
(false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,

View file

@ -1,13 +0,0 @@
use std::sync::mpsc::channel;
fn main() {
let (tx, rx) = channel();
let x = Some(rx);
tx.send(false);
match x {
Some(z) if z.recv().unwrap() => { panic!() },
//~^ ERROR cannot bind by-move into a pattern guard
Some(z) => { assert!(!z.recv().unwrap()); },
None => panic!()
}
}

View file

@ -1,11 +0,0 @@
error[E0008]: cannot bind by-move into a pattern guard
--> $DIR/bind-by-move-no-guards.rs:8:14
|
LL | Some(z) if z.recv().unwrap() => { panic!() },
| ^ moves value into pattern guard
|
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0008`.

View file

@ -8,12 +8,9 @@ fn foo() -> isize {
let mut x = Enum::A(&mut n);
match x {
Enum::A(_) if { x = Enum::B(false); false } => 1,
//~^ ERROR cannot assign in a pattern guard
//~| ERROR cannot assign `x` in match guard
//~^ ERROR cannot assign `x` in match guard
Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
//~^ ERROR cannot mutably borrow in a pattern guard
//~| ERROR cannot assign in a pattern guard
//~| ERROR cannot mutably borrow `x` in match guard
//~^ ERROR cannot mutably borrow `x` in match guard
Enum::A(p) => *p,
Enum::B(_) => 2,
}

View file

@ -1,23 +1,3 @@
error[E0302]: cannot assign in a pattern guard
--> $DIR/borrowck-mutate-in-guard.rs:10:25
|
LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
| ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
error[E0301]: cannot mutably borrow in a pattern guard
--> $DIR/borrowck-mutate-in-guard.rs:13:38
|
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
| ^ borrowed mutably in pattern guard
|
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
error[E0302]: cannot assign in a pattern guard
--> $DIR/borrowck-mutate-in-guard.rs:13:41
|
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
| ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
error[E0510]: cannot assign `x` in match guard
--> $DIR/borrowck-mutate-in-guard.rs:10:25
|
@ -27,7 +7,7 @@ LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
| ^^^^^^^^^^^^^^^^^^ cannot assign
error[E0510]: cannot mutably borrow `x` in match guard
--> $DIR/borrowck-mutate-in-guard.rs:13:33
--> $DIR/borrowck-mutate-in-guard.rs:12:33
|
LL | match x {
| - value is immutable in match guard
@ -35,7 +15,6 @@ LL | match x {
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
| ^^^^^^ cannot mutably borrow
error: aborting due to 5 previous errors
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0301, E0302, E0510.
For more information about an error, try `rustc --explain E0301`.
For more information about this error, try `rustc --explain E0510`.

View file

@ -1,7 +0,0 @@
fn main() {
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {},
//~^ ERROR E0008
_ => {},
}
}

View file

@ -1,11 +0,0 @@
error[E0008]: cannot bind by-move into a pattern guard
--> $DIR/E0008.rs:3:14
|
LL | Some(s) if s.len() == 0 => {},
| ^ moves value into pattern guard
|
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0008`.

View file

@ -1,7 +0,0 @@
fn main() {
match Some(()) {
None => { },
option if option.take().is_none() => {}, //~ ERROR E0301
Some(_) => { } //~^ ERROR E0596
}
}

View file

@ -1,20 +0,0 @@
error[E0301]: cannot mutably borrow in a pattern guard
--> $DIR/E0301.rs:4:19
|
LL | option if option.take().is_none() => {},
| ^^^^^^ borrowed mutably in pattern guard
|
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
error[E0596]: cannot borrow `option` as mutable, as it is immutable for the pattern guard
--> $DIR/E0301.rs:4:19
|
LL | option if option.take().is_none() => {},
| ^^^^^^ cannot borrow as mutable
|
= note: variables bound in patterns are immutable until the end of the pattern guard
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0301, E0596.
For more information about an error, try `rustc --explain E0301`.

View file

@ -1,8 +0,0 @@
fn main() {
match Some(()) {
None => { },
option if { option = None; false } => { }, //~ ERROR E0302
//~^ ERROR cannot assign to `option`, as it is immutable for the pattern guard
Some(_) => { }
}
}

View file

@ -1,17 +0,0 @@
error[E0302]: cannot assign in a pattern guard
--> $DIR/E0302.rs:4:21
|
LL | option if { option = None; false } => { },
| ^^^^^^^^^^^^^ assignment in pattern guard
error[E0594]: cannot assign to `option`, as it is immutable for the pattern guard
--> $DIR/E0302.rs:4:21
|
LL | option if { option = None; false } => { },
| ^^^^^^^^^^^^^ cannot assign
|
= note: variables bound in patterns are immutable until the end of the pattern guard
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0302`.

View file

@ -5,8 +5,6 @@
// See further discussion on rust-lang/rust#24535,
// rust-lang/rfcs#1006, and rust-lang/rfcs#107
#![feature(bind_by_move_pattern_guards)]
fn main() {
rust_issue_24535();
rfcs_issue_1006_1();

View file

@ -5,8 +5,6 @@
// reject it. But I want to make sure that we continue to reject it
// (under NLL) even when that conservaive check goes away.
#![feature(bind_by_move_pattern_guards)]
fn main() {
let mut b = &mut true;
match b {

View file

@ -1,5 +1,5 @@
error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
|
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
| ^^ - mutable borrow occurs due to use of `r` in closure

View file

@ -3,8 +3,6 @@
// run-pass
#![feature(bind_by_move_pattern_guards)]
// Test that z always point to the same temporary.
fn referent_stability() {
let p;

View file

@ -1,8 +1,6 @@
// Test that we have enough false edges to avoid exposing the exact matching
// algorithm in borrow checking.
#![feature(bind_by_move_pattern_guards)]
fn guard_always_precedes_arm(y: i32) {
let mut x;
// x should always be initialized, as the only way to reach the arm is

View file

@ -1,11 +1,11 @@
error[E0381]: use of possibly-uninitialized variable: `x`
--> $DIR/match-cfg-fake-edges.rs:23:13
--> $DIR/match-cfg-fake-edges.rs:21:13
|
LL | x;
| ^ use of possibly-uninitialized `x`
error[E0382]: use of moved value: `x`
--> $DIR/match-cfg-fake-edges.rs:37:13
--> $DIR/match-cfg-fake-edges.rs:35:13
|
LL | let x = String::new();
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait

View file

@ -5,8 +5,6 @@
// 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(bind_by_move_pattern_guards)]
fn ok_mutation_in_guard(mut q: i32) {
match q {
// OK, mutation doesn't change which patterns g matches

View file

@ -1,5 +1,5 @@
error[E0510]: cannot assign `q` in match guard
--> $DIR/match-guards-partially-borrow.rs:57:13
--> $DIR/match-guards-partially-borrow.rs:55:13
|
LL | match q {
| - value is immutable in match guard
@ -8,7 +8,7 @@ LL | q = true;
| ^^^^^^^^ cannot assign
error[E0510]: cannot assign `r` in match guard
--> $DIR/match-guards-partially-borrow.rs:69:13
--> $DIR/match-guards-partially-borrow.rs:67:13
|
LL | match r {
| - value is immutable in match guard
@ -17,7 +17,7 @@ LL | r = true;
| ^^^^^^^^ cannot assign
error[E0510]: cannot assign `t` in match guard
--> $DIR/match-guards-partially-borrow.rs:93:13
--> $DIR/match-guards-partially-borrow.rs:91:13
|
LL | match t {
| - value is immutable in match guard
@ -26,7 +26,7 @@ LL | t = true;
| ^^^^^^^^ cannot assign
error[E0510]: cannot mutably borrow `x.0` in match guard
--> $DIR/match-guards-partially-borrow.rs:107:22
--> $DIR/match-guards-partially-borrow.rs:105:22
|
LL | match x {
| - value is immutable in match guard
@ -35,7 +35,7 @@ LL | Some(ref mut r) => *r = None,
| ^^^^^^^^^ cannot mutably borrow
error[E0506]: cannot assign to `t` because it is borrowed
--> $DIR/match-guards-partially-borrow.rs:119:13
--> $DIR/match-guards-partially-borrow.rs:117:13
|
LL | s if {
| - borrow of `t` occurs here
@ -46,7 +46,7 @@ LL | } => (), // What value should `s` have in the arm?
| - borrow later used here
error[E0510]: cannot assign `y` in match guard
--> $DIR/match-guards-partially-borrow.rs:130:13
--> $DIR/match-guards-partially-borrow.rs:128:13
|
LL | match *y {
| -- value is immutable in match guard
@ -55,7 +55,7 @@ LL | y = &true;
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `z` in match guard
--> $DIR/match-guards-partially-borrow.rs:141:13
--> $DIR/match-guards-partially-borrow.rs:139:13
|
LL | match z {
| - value is immutable in match guard
@ -64,7 +64,7 @@ LL | z = &true;
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `a` in match guard
--> $DIR/match-guards-partially-borrow.rs:153:13
--> $DIR/match-guards-partially-borrow.rs:151:13
|
LL | match a {
| - value is immutable in match guard
@ -73,7 +73,7 @@ LL | a = &true;
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `b` in match guard
--> $DIR/match-guards-partially-borrow.rs:164:13
--> $DIR/match-guards-partially-borrow.rs:162:13
|
LL | match b {
| - value is immutable in match guard

View file

@ -4,8 +4,6 @@
// run-pass
#![feature(bind_by_move_pattern_guards)]
use std::sync::mpsc::channel;
fn main() {

View file

@ -1,10 +0,0 @@
error: compilation successful
--> $DIR/feature-gate.rs:36:1
|
LL | / fn main() {
LL | | foo(107)
LL | | }
| |_^
error: aborting due to previous error

View file

@ -1,10 +0,0 @@
error: compilation successful
--> $DIR/feature-gate.rs:36:1
|
LL | / fn main() {
LL | | foo(107)
LL | | }
| |_^
error: aborting due to previous error

View file

@ -1,10 +0,0 @@
error: compilation successful
--> $DIR/feature-gate.rs:41:1
|
LL | / fn main() {
LL | | foo(107)
LL | | }
| |_^
error: aborting due to previous error

View file

@ -1,10 +0,0 @@
error: compilation successful
--> $DIR/feature-gate.rs:41:1
|
LL | / fn main() {
LL | | foo(107)
LL | | }
| |_^
error: aborting due to previous error

View file

@ -1,11 +0,0 @@
error[E0008]: cannot bind by-move into a pattern guard
--> $DIR/feature-gate.rs:28:16
|
LL | A { a: v } if *v == 42 => v,
| ^ moves value into pattern guard
|
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0008`.

View file

@ -1,40 +0,0 @@
// Check that pattern-guards with move-bound variables is only allowed
// with the appropriate set of feature gates. (Note that we require
// the code to opt into MIR-borrowck in *some* way before the feature
// will work; we use the revision system here to enumerate a number of
// ways that opt-in could occur.)
// gate-test-bind_by_move_pattern_guards
// revisions: no_gate gate_and_2015 gate_and_2018
// (We're already testing NLL behavior quite explicitly, no need for compare-mode=nll.)
// ignore-compare-mode-nll
#![feature(rustc_attrs)]
#![cfg_attr(gate_and_2015, feature(bind_by_move_pattern_guards))]
#![cfg_attr(gate_and_2018, feature(bind_by_move_pattern_guards))]
//[gate_and_2015] edition:2015
//[gate_and_2018] edition:2018
struct A { a: Box<i32> }
fn foo(n: i32) {
let x = A { a: Box::new(n) };
let _y = match x {
A { a: v } if *v == 42 => v,
//[no_gate]~^ ERROR cannot bind by-move into a pattern guard
_ => Box::new(0)
};
}
#[rustc_error]
fn main() {
foo(107)
}
//[gate_and_2015]~^^^ ERROR compilation successful
//[gate_and_2018]~^^^^ ERROR compilation successful

View file

@ -0,0 +1,11 @@
// This test used to emit E0008 but now passed since `bind_by_move_pattern_guards`
// have been stabilized.
// check-pass
fn main() {
match Some("hi".to_string()) {
Some(s) if s.len() == 0 => {},
_ => {},
}
}

View file

@ -1,5 +1,3 @@
#![feature(bind_by_move_pattern_guards)]
// run-pass
struct A { a: Box<i32> }

View file

@ -1,5 +1,3 @@
#![feature(bind_by_move_pattern_guards)]
enum VecWrapper { A(Vec<i32>) }
fn foo(x: VecWrapper) -> usize {

View file

@ -1,5 +1,5 @@
error[E0507]: cannot move out of `v` in pattern guard
--> $DIR/rfc-reject-double-move-across-arms.rs:7:36
--> $DIR/rfc-reject-double-move-across-arms.rs:5:36
|
LL | VecWrapper::A(v) if { drop(v); false } => 1,
| ^ move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait

View file

@ -1,5 +1,3 @@
#![feature(bind_by_move_pattern_guards)]
struct A { a: Box<i32> }
fn foo(n: i32) {

View file

@ -1,5 +1,5 @@
error[E0507]: cannot move out of `v` in pattern guard
--> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
--> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
|
LL | A { a: v } if { drop(v); true } => v,
| ^ move occurs because `v` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait