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:
commit
45859b7ca7
42 changed files with 51 additions and 427 deletions
|
@ -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)]
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.)
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
|
@ -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`.
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
match Some("hi".to_string()) {
|
||||
Some(s) if s.len() == 0 => {},
|
||||
//~^ ERROR E0008
|
||||
_ => {},
|
||||
}
|
||||
}
|
|
@ -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`.
|
|
@ -1,7 +0,0 @@
|
|||
fn main() {
|
||||
match Some(()) {
|
||||
None => { },
|
||||
option if option.take().is_none() => {}, //~ ERROR E0301
|
||||
Some(_) => { } //~^ ERROR E0596
|
||||
}
|
||||
}
|
|
@ -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`.
|
|
@ -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(_) => { }
|
||||
}
|
||||
}
|
|
@ -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`.
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
// run-pass
|
||||
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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`.
|
|
@ -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
|
|
@ -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 => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
// run-pass
|
||||
|
||||
struct A { a: Box<i32> }
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
enum VecWrapper { A(Vec<i32>) }
|
||||
|
||||
fn foo(x: VecWrapper) -> usize {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
struct A { a: Box<i32> }
|
||||
|
||||
fn foo(n: i32) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue