Auto merge of #63059 - Centril:sound-bind-by-move, r=matthewjasper
Make `#![feature(bind_by_move_pattern_guards)]` sound without `#[feature(nll)]` Implements https://github.com/rust-lang/rust/issues/15287#issuecomment-507054617 making `#![feature(bind_by_move_pattern_guards)]]` sound without also having `#![feature(nll)]`. The logic here is that if we see a `match` guard, we will refuse to downgrade NLL errors to warnings. This is in preparation for hopefully stabilizing the former feature in https://github.com/rust-lang/rust/pull/63118. As fall out from the implementation we also: Fixes https://github.com/rust-lang/rust/issues/31287 Fixes https://github.com/rust-lang/rust/issues/27282 r? @matthewjasper
This commit is contained in:
commit
6e0d27d936
35 changed files with 205 additions and 186 deletions
|
|
@ -461,7 +461,7 @@ rustc_queries! {
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeChecking {
|
TypeChecking {
|
||||||
query check_match(key: DefId) -> () {
|
query check_match(key: DefId) -> SignalledError {
|
||||||
cache_on_disk_if { key.is_local() }
|
cache_on_disk_if { key.is_local() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use crate::hir::def::{DefKind, Export};
|
||||||
use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs};
|
use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs};
|
||||||
use crate::infer::canonical::{self, Canonical};
|
use crate::infer::canonical::{self, Canonical};
|
||||||
use crate::lint;
|
use crate::lint;
|
||||||
use crate::middle::borrowck::BorrowCheckResult;
|
use crate::middle::borrowck::{BorrowCheckResult, SignalledError};
|
||||||
use crate::middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule};
|
use crate::middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule};
|
||||||
use crate::middle::cstore::{NativeLibraryKind, DepKind, CrateSource};
|
use crate::middle::cstore::{NativeLibraryKind, DepKind, CrateSource};
|
||||||
use crate::middle::privacy::AccessLevels;
|
use crate::middle::privacy::AccessLevels;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,13 @@ fn borrowck(tcx: TyCtxt<'_>, owner_def_id: DefId) -> &BorrowCheckResult {
|
||||||
|
|
||||||
debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
|
debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
|
||||||
|
|
||||||
|
let signalled_error = tcx.check_match(owner_def_id);
|
||||||
|
if let SignalledError::SawSomeError = signalled_error {
|
||||||
|
return tcx.arena.alloc(BorrowCheckResult {
|
||||||
|
signalled_any_error: SignalledError::SawSomeError,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap();
|
let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap();
|
||||||
|
|
||||||
match tcx.hir().get(owner_id) {
|
match tcx.hir().get(owner_id) {
|
||||||
|
|
|
||||||
|
|
@ -1989,7 +1989,7 @@ When matching on a variable it cannot be mutated in the match guards, as this
|
||||||
could cause the match to be non-exhaustive:
|
could cause the match to be non-exhaustive:
|
||||||
|
|
||||||
```compile_fail,E0510
|
```compile_fail,E0510
|
||||||
#![feature(nll, bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
let mut x = Some(0);
|
let mut x = Some(0);
|
||||||
match x {
|
match x {
|
||||||
None => (),
|
None => (),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use super::_match::WitnessPreference::*;
|
||||||
|
|
||||||
use super::{Pattern, PatternContext, PatternError, PatternKind};
|
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::{ConsumeMode, Delegate, ExprUseVisitor};
|
||||||
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
|
use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
use rustc::middle::expr_use_visitor as euv;
|
||||||
|
|
@ -26,21 +27,24 @@ use std::slice;
|
||||||
|
|
||||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||||
|
|
||||||
pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
|
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) -> SignalledError {
|
||||||
let body_id = if let Some(id) = tcx.hir().as_local_hir_id(def_id) {
|
let body_id = if let Some(id) = tcx.hir().as_local_hir_id(def_id) {
|
||||||
tcx.hir().body_owned_by(id)
|
tcx.hir().body_owned_by(id)
|
||||||
} else {
|
} else {
|
||||||
return;
|
return SignalledError::NoErrorsSeen;
|
||||||
};
|
};
|
||||||
|
|
||||||
MatchVisitor {
|
let mut visitor = MatchVisitor {
|
||||||
tcx,
|
tcx,
|
||||||
body_owner: def_id,
|
body_owner: def_id,
|
||||||
tables: tcx.body_tables(body_id),
|
tables: tcx.body_tables(body_id),
|
||||||
region_scope_tree: &tcx.region_scope_tree(def_id),
|
region_scope_tree: &tcx.region_scope_tree(def_id),
|
||||||
param_env: tcx.param_env(def_id),
|
param_env: tcx.param_env(def_id),
|
||||||
identity_substs: InternalSubsts::identity_for_item(tcx, def_id),
|
identity_substs: InternalSubsts::identity_for_item(tcx, def_id),
|
||||||
}.visit_body(tcx.hir().body(body_id));
|
signalled_error: SignalledError::NoErrorsSeen,
|
||||||
|
};
|
||||||
|
visitor.visit_body(tcx.hir().body(body_id));
|
||||||
|
visitor.signalled_error
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> {
|
fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> {
|
||||||
|
|
@ -54,6 +58,7 @@ struct MatchVisitor<'a, 'tcx> {
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
identity_substs: SubstsRef<'tcx>,
|
identity_substs: SubstsRef<'tcx>,
|
||||||
region_scope_tree: &'a region::ScopeTree,
|
region_scope_tree: &'a region::ScopeTree,
|
||||||
|
signalled_error: SignalledError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
|
||||||
|
|
@ -64,11 +69,8 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
|
||||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
|
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
|
||||||
intravisit::walk_expr(self, ex);
|
intravisit::walk_expr(self, ex);
|
||||||
|
|
||||||
match ex.node {
|
if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.node {
|
||||||
hir::ExprKind::Match(ref scrut, ref arms, source) => {
|
self.check_match(scrut, arms, source);
|
||||||
self.check_match(scrut, arms, source);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +132,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||||
fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
|
fn check_patterns(&mut self, has_guard: bool, pats: &[P<Pat>]) {
|
||||||
check_legality_of_move_bindings(self, has_guard, pats);
|
check_legality_of_move_bindings(self, has_guard, pats);
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
check_legality_of_bindings_in_at_patterns(self, pat);
|
check_legality_of_bindings_in_at_patterns(self, pat);
|
||||||
|
|
@ -138,11 +140,11 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_match(
|
fn check_match(
|
||||||
&self,
|
&mut self,
|
||||||
scrut: &hir::Expr,
|
scrut: &hir::Expr,
|
||||||
arms: &'tcx [hir::Arm],
|
arms: &'tcx [hir::Arm],
|
||||||
source: hir::MatchSource)
|
source: hir::MatchSource
|
||||||
{
|
) {
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
// First, check legality of move bindings.
|
// First, check legality of move bindings.
|
||||||
self.check_patterns(arm.guard.is_some(), &arm.pats);
|
self.check_patterns(arm.guard.is_some(), &arm.pats);
|
||||||
|
|
@ -150,6 +152,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||||
// Second, if there is a guard on each arm, make sure it isn't
|
// Second, if there is a guard on each arm, make sure it isn't
|
||||||
// assigning or borrowing anything mutably.
|
// assigning or borrowing anything mutably.
|
||||||
if let Some(ref guard) = arm.guard {
|
if let Some(ref guard) = arm.guard {
|
||||||
|
self.signalled_error = SignalledError::SawSomeError;
|
||||||
if !self.tcx.features().bind_by_move_pattern_guards {
|
if !self.tcx.features().bind_by_move_pattern_guards {
|
||||||
check_for_mutation_in_guard(self, &guard);
|
check_for_mutation_in_guard(self, &guard);
|
||||||
}
|
}
|
||||||
|
|
@ -548,7 +551,7 @@ fn maybe_point_at_variant(
|
||||||
|
|
||||||
// Legality of move bindings checking
|
// Legality of move bindings checking
|
||||||
fn check_legality_of_move_bindings(
|
fn check_legality_of_move_bindings(
|
||||||
cx: &MatchVisitor<'_, '_>,
|
cx: &mut MatchVisitor<'_, '_>,
|
||||||
has_guard: bool,
|
has_guard: bool,
|
||||||
pats: &[P<Pat>],
|
pats: &[P<Pat>],
|
||||||
) {
|
) {
|
||||||
|
|
@ -565,7 +568,12 @@ fn check_legality_of_move_bindings(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let span_vec = &mut Vec::new();
|
let span_vec = &mut Vec::new();
|
||||||
let check_move = |p: &Pat, sub: Option<&Pat>, span_vec: &mut Vec<Span>| {
|
let check_move = |
|
||||||
|
cx: &mut MatchVisitor<'_, '_>,
|
||||||
|
p: &Pat,
|
||||||
|
sub: Option<&Pat>,
|
||||||
|
span_vec: &mut Vec<Span>,
|
||||||
|
| {
|
||||||
// check legality of moving out of the enum
|
// check legality of moving out of the enum
|
||||||
|
|
||||||
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
|
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
|
||||||
|
|
@ -574,15 +582,17 @@ fn check_legality_of_move_bindings(
|
||||||
"cannot bind by-move with sub-bindings")
|
"cannot bind by-move with sub-bindings")
|
||||||
.span_label(p.span, "binds an already bound by-move value by moving it")
|
.span_label(p.span, "binds an already bound by-move value by moving it")
|
||||||
.emit();
|
.emit();
|
||||||
} else if has_guard && !cx.tcx.features().bind_by_move_pattern_guards {
|
} else if has_guard {
|
||||||
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
|
if !cx.tcx.features().bind_by_move_pattern_guards {
|
||||||
"cannot bind by-move into a pattern guard");
|
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
|
||||||
err.span_label(p.span, "moves value into pattern guard");
|
"cannot bind by-move into a pattern guard");
|
||||||
if cx.tcx.sess.opts.unstable_features.is_nightly_build() {
|
err.span_label(p.span, "moves value into pattern guard");
|
||||||
err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \
|
if cx.tcx.sess.opts.unstable_features.is_nightly_build() {
|
||||||
crate attributes to enable");
|
err.help("add `#![feature(bind_by_move_pattern_guards)]` to the \
|
||||||
|
crate attributes to enable");
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
}
|
}
|
||||||
err.emit();
|
|
||||||
} else if let Some(_by_ref_span) = by_ref_span {
|
} else if let Some(_by_ref_span) = by_ref_span {
|
||||||
span_vec.push(p.span);
|
span_vec.push(p.span);
|
||||||
}
|
}
|
||||||
|
|
@ -596,7 +606,7 @@ fn check_legality_of_move_bindings(
|
||||||
ty::BindByValue(..) => {
|
ty::BindByValue(..) => {
|
||||||
let pat_ty = cx.tables.node_type(p.hir_id);
|
let pat_ty = cx.tables.node_type(p.hir_id);
|
||||||
if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
|
if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
|
||||||
check_move(p, sub.as_ref().map(|p| &**p), span_vec);
|
check_move(cx, p, sub.as_ref().map(|p| &**p), span_vec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
warning[E0507]: cannot move out of `foo` in pattern guard
|
warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
|
||||||
--> $DIR/borrowck-migrate-to-nll.rs:26:18
|
--> $DIR/borrowck-migrate-to-nll.rs:28:21
|
||||||
|
|
|
|
||||||
LL | (|| { let bar = foo; bar.take() })();
|
LL | let x = &mut block;
|
||||||
| ^^ ---
|
| ---------- mutable borrow occurs here
|
||||||
| | |
|
LL | let p: &'a u8 = &*block.current;
|
||||||
| | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait
|
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
|
||||||
| | move occurs due to use in closure
|
LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes)
|
||||||
| move out of `foo` occurs here
|
LL | drop(x);
|
||||||
|
| - mutable borrow later used here
|
||||||
|
|
|
|
||||||
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
|
|
||||||
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
|
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
|
||||||
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
|
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
|
||||||
= note: for more information, try `rustc --explain E0729`
|
= note: for more information, try `rustc --explain E0729`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// This is a test of the borrowck migrate mode. It leverages #27282, a
|
// This is a test of the borrowck migrate mode. It leverages #38899, a
|
||||||
// bug that is fixed by NLL: this code is (unsoundly) accepted by
|
// bug that is fixed by NLL: this code is (unsoundly) accepted by
|
||||||
// AST-borrowck, but is correctly rejected by the NLL borrowck.
|
// AST-borrowck, but is correctly rejected by the NLL borrowck.
|
||||||
//
|
//
|
||||||
|
|
@ -18,15 +18,17 @@
|
||||||
//[zflag] run-pass
|
//[zflag] run-pass
|
||||||
//[edition] run-pass
|
//[edition] run-pass
|
||||||
|
|
||||||
fn main() {
|
pub struct Block<'a> {
|
||||||
match Some(&4) {
|
current: &'a u8,
|
||||||
None => {},
|
unrelated: &'a u8,
|
||||||
ref mut foo
|
|
||||||
if {
|
|
||||||
(|| { let bar = foo; bar.take() })();
|
|
||||||
false
|
|
||||||
} => {},
|
|
||||||
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
|
|
||||||
_ => println!("Here is some supposedly unreachable code."),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bump<'a>(mut block: &mut Block<'a>) {
|
||||||
|
let x = &mut block;
|
||||||
|
let p: &'a u8 = &*block.current;
|
||||||
|
// (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes)
|
||||||
|
drop(x);
|
||||||
|
drop(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
warning[E0507]: cannot move out of `foo` in pattern guard
|
warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
|
||||||
--> $DIR/borrowck-migrate-to-nll.rs:26:18
|
--> $DIR/borrowck-migrate-to-nll.rs:28:21
|
||||||
|
|
|
|
||||||
LL | (|| { let bar = foo; bar.take() })();
|
LL | let x = &mut block;
|
||||||
| ^^ ---
|
| ---------- mutable borrow occurs here
|
||||||
| | |
|
LL | let p: &'a u8 = &*block.current;
|
||||||
| | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait
|
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
|
||||||
| | move occurs due to use in closure
|
LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes)
|
||||||
| move out of `foo` occurs here
|
LL | drop(x);
|
||||||
|
| - mutable borrow later used here
|
||||||
|
|
|
|
||||||
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
|
|
||||||
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
|
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
|
||||||
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
|
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
|
||||||
= note: for more information, try `rustc --explain E0729`
|
= note: for more information, try `rustc --explain E0729`
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
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:15: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:15: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
|
|
||||||
|
|
|
||||||
LL | match x {
|
|
||||||
| - value is immutable in match guard
|
|
||||||
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:15:33
|
|
||||||
|
|
|
||||||
LL | match x {
|
|
||||||
| - value is immutable in match guard
|
|
||||||
...
|
|
||||||
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
|
||||||
| ^^^^^^ cannot mutably borrow
|
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0301, E0302, E0510.
|
|
||||||
For more information about an error, try `rustc --explain E0301`.
|
|
||||||
|
|
@ -9,15 +9,11 @@ fn foo() -> isize {
|
||||||
match x {
|
match x {
|
||||||
Enum::A(_) if { x = Enum::B(false); false } => 1,
|
Enum::A(_) if { x = Enum::B(false); false } => 1,
|
||||||
//~^ ERROR cannot assign in a pattern guard
|
//~^ ERROR cannot assign in a pattern guard
|
||||||
//~| WARN cannot assign `x` in match guard
|
//~| ERROR cannot assign `x` in match guard
|
||||||
//~| WARN this error has been downgraded to a warning for backwards compatibility
|
|
||||||
//~| WARN this represents potential undefined behavior in your code and this warning will
|
|
||||||
Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
||||||
//~^ ERROR cannot mutably borrow in a pattern guard
|
//~^ ERROR cannot mutably borrow in a pattern guard
|
||||||
//~| ERROR cannot assign in a pattern guard
|
//~| ERROR cannot assign in a pattern guard
|
||||||
//~| WARN cannot mutably borrow `x` in match guard
|
//~| ERROR cannot mutably borrow `x` in match guard
|
||||||
//~| WARN this error has been downgraded to a warning for backwards compatibility
|
|
||||||
//~| WARN this represents potential undefined behavior in your code and this warning will
|
|
||||||
Enum::A(p) => *p,
|
Enum::A(p) => *p,
|
||||||
Enum::B(_) => 2,
|
Enum::B(_) => 2,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
|
||||||
| ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
|
| ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
|
||||||
|
|
||||||
error[E0301]: cannot mutably borrow in a pattern guard
|
error[E0301]: cannot mutably borrow in a pattern guard
|
||||||
--> $DIR/borrowck-mutate-in-guard.rs:15:38
|
--> $DIR/borrowck-mutate-in-guard.rs:13:38
|
||||||
|
|
|
|
||||||
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
||||||
| ^ borrowed mutably in pattern guard
|
| ^ borrowed mutably in pattern guard
|
||||||
|
|
@ -13,37 +13,29 @@ LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
||||||
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
|
= help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0302]: cannot assign in a pattern guard
|
error[E0302]: cannot assign in a pattern guard
|
||||||
--> $DIR/borrowck-mutate-in-guard.rs:15:41
|
--> $DIR/borrowck-mutate-in-guard.rs:13:41
|
||||||
|
|
|
|
||||||
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
||||||
| ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
|
| ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
|
||||||
|
|
||||||
warning[E0510]: cannot assign `x` in match guard
|
error[E0510]: cannot assign `x` in match guard
|
||||||
--> $DIR/borrowck-mutate-in-guard.rs:10:25
|
--> $DIR/borrowck-mutate-in-guard.rs:10:25
|
||||||
|
|
|
|
||||||
LL | match x {
|
LL | match x {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
|
LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
|
||||||
| ^^^^^^^^^^^^^^^^^^ cannot assign
|
| ^^^^^^^^^^^^^^^^^^ cannot assign
|
||||||
|
|
|
||||||
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
|
|
||||||
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
|
|
||||||
= note: for more information, try `rustc --explain E0729`
|
|
||||||
|
|
||||||
warning[E0510]: cannot mutably borrow `x` in match guard
|
error[E0510]: cannot mutably borrow `x` in match guard
|
||||||
--> $DIR/borrowck-mutate-in-guard.rs:15:33
|
--> $DIR/borrowck-mutate-in-guard.rs:13:33
|
||||||
|
|
|
|
||||||
LL | match x {
|
LL | match x {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
...
|
...
|
||||||
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
|
||||||
| ^^^^^^ cannot mutably borrow
|
| ^^^^^^ cannot mutably borrow
|
||||||
|
|
|
||||||
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
|
|
||||||
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
|
|
||||||
= note: for more information, try `rustc --explain E0729`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0301, E0302, E0510.
|
Some errors have detailed explanations: E0301, E0302, E0510.
|
||||||
For more information about an error, try `rustc --explain E0301`.
|
For more information about an error, try `rustc --explain E0301`.
|
||||||
|
|
|
||||||
13
src/test/ui/borrowck/issue-27282-mutation-in-guard.rs
Normal file
13
src/test/ui/borrowck/issue-27282-mutation-in-guard.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
fn main() {
|
||||||
|
match Some(&4) {
|
||||||
|
None => {},
|
||||||
|
ref mut foo
|
||||||
|
if {
|
||||||
|
(|| { let bar = foo; bar.take() })();
|
||||||
|
//~^ ERROR cannot move out of `foo` in pattern guard
|
||||||
|
false
|
||||||
|
} => {},
|
||||||
|
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
|
||||||
|
_ => println!("Here is some supposedly unreachable code."),
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr
Normal file
15
src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0507]: cannot move out of `foo` in pattern guard
|
||||||
|
--> $DIR/issue-27282-mutation-in-guard.rs:6:18
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^ ---
|
||||||
|
| | |
|
||||||
|
| | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait
|
||||||
|
| | move occurs due to use in closure
|
||||||
|
| move out of `foo` occurs here
|
||||||
|
|
|
||||||
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0507`.
|
||||||
8
src/test/ui/borrowck/issue-31287-drop-in-guard.rs
Normal file
8
src/test/ui/borrowck/issue-31287-drop-in-guard.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
fn main() {
|
||||||
|
let a = Some("...".to_owned());
|
||||||
|
let b = match a {
|
||||||
|
Some(_) if { drop(a); false } => None,
|
||||||
|
x => x, //~ ERROR use of moved value: `a`
|
||||||
|
};
|
||||||
|
println!("{:?}", b);
|
||||||
|
}
|
||||||
14
src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
Normal file
14
src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0382]: use of moved value: `a`
|
||||||
|
--> $DIR/issue-31287-drop-in-guard.rs:5:9
|
||||||
|
|
|
||||||
|
LL | let a = Some("...".to_owned());
|
||||||
|
| - move occurs because `a` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
|
||||||
|
LL | let b = match a {
|
||||||
|
LL | Some(_) if { drop(a); false } => None,
|
||||||
|
| - value moved here
|
||||||
|
LL | x => x,
|
||||||
|
| ^ value used here after move
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
||||||
|
|
@ -5,9 +5,7 @@
|
||||||
// reject it. But I want to make sure that we continue to reject it
|
// reject it. But I want to make sure that we continue to reject it
|
||||||
// (under NLL) even when that conservaive check goes away.
|
// (under NLL) even when that conservaive check goes away.
|
||||||
|
|
||||||
|
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
#![feature(nll)]
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut b = &mut true;
|
let mut b = &mut true;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
|
error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
|
||||||
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:16:25
|
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
|
||||||
|
|
|
|
||||||
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
|
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
|
||||||
| ^^ - mutable borrow occurs due to use of `r` in closure
|
| ^^ - mutable borrow occurs due to use of `r` in closure
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
// run-pass
|
// run-pass
|
||||||
|
|
||||||
#![feature(nll, bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
// Test that z always point to the same temporary.
|
// Test that z always point to the same temporary.
|
||||||
fn referent_stability() {
|
fn referent_stability() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Test that we have enough false edges to avoid exposing the exact matching
|
// Test that we have enough false edges to avoid exposing the exact matching
|
||||||
// algorithm in borrow checking.
|
// algorithm in borrow checking.
|
||||||
|
|
||||||
#![feature(nll, bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
fn guard_always_precedes_arm(y: i32) {
|
fn guard_always_precedes_arm(y: i32) {
|
||||||
let mut x;
|
let mut x;
|
||||||
|
|
@ -41,18 +41,4 @@ fn guard_may_be_taken(y: bool) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
|
|
||||||
let r = &mut y.1;
|
|
||||||
// We don't actually test y.1 to select the second arm, but we don't want
|
|
||||||
// borrowck results to be based on the order we match patterns.
|
|
||||||
match y {
|
|
||||||
(false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed
|
|
||||||
(true, _) => {
|
|
||||||
r;
|
|
||||||
2
|
|
||||||
}
|
|
||||||
(false, _) => 3,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,7 @@ LL | true => {
|
||||||
LL | x;
|
LL | x;
|
||||||
| ^ value used here after move
|
| ^ value used here after move
|
||||||
|
|
||||||
error[E0503]: cannot use `y.1` because it was mutably borrowed
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/match-cfg-fake-edges.rs:49:17
|
|
||||||
|
|
|
||||||
LL | let r = &mut y.1;
|
|
||||||
| -------- borrow of `y.1` occurs here
|
|
||||||
...
|
|
||||||
LL | (false, true) => 1,
|
|
||||||
| ^^^^ use of borrowed `y.1`
|
|
||||||
LL | (true, _) => {
|
|
||||||
LL | r;
|
|
||||||
| - borrow later used here
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
Some errors have detailed explanations: E0381, E0382.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0381, E0382, E0503.
|
|
||||||
For more information about an error, try `rustc --explain E0381`.
|
For more information about an error, try `rustc --explain E0381`.
|
||||||
|
|
|
||||||
20
src/test/ui/nll/match-cfg-fake-edges2.rs
Normal file
20
src/test/ui/nll/match-cfg-fake-edges2.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Test that we have enough false edges to avoid exposing the exact matching
|
||||||
|
// algorithm in borrow checking.
|
||||||
|
|
||||||
|
#![feature(nll)]
|
||||||
|
|
||||||
|
fn all_previous_tests_may_be_done(y: &mut (bool, bool)) {
|
||||||
|
let r = &mut y.1;
|
||||||
|
// We don't actually test y.1 to select the second arm, but we don't want
|
||||||
|
// borrowck results to be based on the order we match patterns.
|
||||||
|
match y {
|
||||||
|
(false, true) => 1, //~ ERROR cannot use `y.1` because it was mutably borrowed
|
||||||
|
(true, _) => {
|
||||||
|
r;
|
||||||
|
2
|
||||||
|
}
|
||||||
|
(false, _) => 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
15
src/test/ui/nll/match-cfg-fake-edges2.stderr
Normal file
15
src/test/ui/nll/match-cfg-fake-edges2.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0503]: cannot use `y.1` because it was mutably borrowed
|
||||||
|
--> $DIR/match-cfg-fake-edges2.rs:11:17
|
||||||
|
|
|
||||||
|
LL | let r = &mut y.1;
|
||||||
|
| -------- borrow of `y.1` occurs here
|
||||||
|
...
|
||||||
|
LL | (false, true) => 1,
|
||||||
|
| ^^^^ use of borrowed `y.1`
|
||||||
|
LL | (true, _) => {
|
||||||
|
LL | r;
|
||||||
|
| - borrow later used here
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0503`.
|
||||||
|
|
@ -5,9 +5,7 @@
|
||||||
// Test that we don't allow mutating the value being matched on in a way that
|
// 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.
|
// changes which patterns it matches, until we have chosen an arm.
|
||||||
|
|
||||||
|
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
#![feature(nll)]
|
|
||||||
|
|
||||||
fn ok_mutation_in_guard(mut q: i32) {
|
fn ok_mutation_in_guard(mut q: i32) {
|
||||||
match q {
|
match q {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0510]: cannot assign `q` in match guard
|
error[E0510]: cannot assign `q` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:59:13
|
--> $DIR/match-guards-partially-borrow.rs:57:13
|
||||||
|
|
|
|
||||||
LL | match q {
|
LL | match q {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
@ -8,7 +8,7 @@ LL | q = true;
|
||||||
| ^^^^^^^^ cannot assign
|
| ^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error[E0510]: cannot assign `r` in match guard
|
error[E0510]: cannot assign `r` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:71:13
|
--> $DIR/match-guards-partially-borrow.rs:69:13
|
||||||
|
|
|
|
||||||
LL | match r {
|
LL | match r {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
@ -17,7 +17,7 @@ LL | r = true;
|
||||||
| ^^^^^^^^ cannot assign
|
| ^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error[E0510]: cannot assign `t` in match guard
|
error[E0510]: cannot assign `t` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:95:13
|
--> $DIR/match-guards-partially-borrow.rs:93:13
|
||||||
|
|
|
|
||||||
LL | match t {
|
LL | match t {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
@ -26,7 +26,7 @@ LL | t = true;
|
||||||
| ^^^^^^^^ cannot assign
|
| ^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error[E0510]: cannot mutably borrow `x.0` in match guard
|
error[E0510]: cannot mutably borrow `x.0` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:109:22
|
--> $DIR/match-guards-partially-borrow.rs:107:22
|
||||||
|
|
|
|
||||||
LL | match x {
|
LL | match x {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
@ -35,7 +35,7 @@ LL | Some(ref mut r) => *r = None,
|
||||||
| ^^^^^^^^^ cannot mutably borrow
|
| ^^^^^^^^^ cannot mutably borrow
|
||||||
|
|
||||||
error[E0506]: cannot assign to `t` because it is borrowed
|
error[E0506]: cannot assign to `t` because it is borrowed
|
||||||
--> $DIR/match-guards-partially-borrow.rs:121:13
|
--> $DIR/match-guards-partially-borrow.rs:119:13
|
||||||
|
|
|
|
||||||
LL | s if {
|
LL | s if {
|
||||||
| - borrow of `t` occurs here
|
| - borrow of `t` occurs here
|
||||||
|
|
@ -46,7 +46,7 @@ LL | } => (), // What value should `s` have in the arm?
|
||||||
| - borrow later used here
|
| - borrow later used here
|
||||||
|
|
||||||
error[E0510]: cannot assign `y` in match guard
|
error[E0510]: cannot assign `y` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:132:13
|
--> $DIR/match-guards-partially-borrow.rs:130:13
|
||||||
|
|
|
|
||||||
LL | match *y {
|
LL | match *y {
|
||||||
| -- value is immutable in match guard
|
| -- value is immutable in match guard
|
||||||
|
|
@ -55,7 +55,7 @@ LL | y = &true;
|
||||||
| ^^^^^^^^^ cannot assign
|
| ^^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error[E0510]: cannot assign `z` in match guard
|
error[E0510]: cannot assign `z` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:143:13
|
--> $DIR/match-guards-partially-borrow.rs:141:13
|
||||||
|
|
|
|
||||||
LL | match z {
|
LL | match z {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
@ -64,7 +64,7 @@ LL | z = &true;
|
||||||
| ^^^^^^^^^ cannot assign
|
| ^^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error[E0510]: cannot assign `a` in match guard
|
error[E0510]: cannot assign `a` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:155:13
|
--> $DIR/match-guards-partially-borrow.rs:153:13
|
||||||
|
|
|
|
||||||
LL | match a {
|
LL | match a {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
@ -73,7 +73,7 @@ LL | a = &true;
|
||||||
| ^^^^^^^^^ cannot assign
|
| ^^^^^^^^^ cannot assign
|
||||||
|
|
||||||
error[E0510]: cannot assign `b` in match guard
|
error[E0510]: cannot assign `b` in match guard
|
||||||
--> $DIR/match-guards-partially-borrow.rs:166:13
|
--> $DIR/match-guards-partially-borrow.rs:164:13
|
||||||
|
|
|
|
||||||
LL | match b {
|
LL | match b {
|
||||||
| - value is immutable in match guard
|
| - value is immutable in match guard
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// rust-lang/rust#2329), that starts passing with this feature in
|
// rust-lang/rust#2329), that starts passing with this feature in
|
||||||
// place.
|
// place.
|
||||||
|
|
||||||
// build-pass (FIXME(62277): could be check-pass?)
|
// run-pass
|
||||||
|
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
|
|
@ -12,6 +12,7 @@ fn main() {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let x = Some(rx);
|
let x = Some(rx);
|
||||||
tx.send(false);
|
tx.send(false);
|
||||||
|
tx.send(false);
|
||||||
match x {
|
match x {
|
||||||
Some(z) if z.recv().unwrap() => { panic!() },
|
Some(z) if z.recv().unwrap() => { panic!() },
|
||||||
Some(z) => { assert!(!z.recv().unwrap()); },
|
Some(z) => { assert!(!z.recv().unwrap()); },
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error: compilation successful
|
error: compilation successful
|
||||||
--> $DIR/feature-gate.rs:41:1
|
--> $DIR/feature-gate.rs:36:1
|
||||||
|
|
|
|
||||||
LL | / fn main() {
|
LL | / fn main() {
|
||||||
LL | | foo(107)
|
LL | | foo(107)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error: compilation successful
|
error: compilation successful
|
||||||
--> $DIR/feature-gate.rs:41:1
|
--> $DIR/feature-gate.rs:36:1
|
||||||
|
|
|
|
||||||
LL | / fn main() {
|
LL | / fn main() {
|
||||||
LL | | foo(107)
|
LL | | foo(107)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0008]: cannot bind by-move into a pattern guard
|
error[E0008]: cannot bind by-move into a pattern guard
|
||||||
--> $DIR/feature-gate.rs:33:16
|
--> $DIR/feature-gate.rs:28:16
|
||||||
|
|
|
|
||||||
LL | A { a: v } if *v == 42 => v,
|
LL | A { a: v } if *v == 42 => v,
|
||||||
| ^ moves value into pattern guard
|
| ^ moves value into pattern guard
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
// gate-test-bind_by_move_pattern_guards
|
// gate-test-bind_by_move_pattern_guards
|
||||||
|
|
||||||
// revisions: no_gate gate_and_2015 gate_and_2018 gate_and_znll gate_and_feature_nll
|
// revisions: no_gate gate_and_2015 gate_and_2018
|
||||||
|
|
||||||
// (We're already testing NLL behavior quite explicitly, no need for compare-mode=nll.)
|
// (We're already testing NLL behavior quite explicitly, no need for compare-mode=nll.)
|
||||||
// ignore-compare-mode-nll
|
// ignore-compare-mode-nll
|
||||||
|
|
@ -15,14 +15,9 @@
|
||||||
|
|
||||||
#![cfg_attr(gate_and_2015, feature(bind_by_move_pattern_guards))]
|
#![cfg_attr(gate_and_2015, feature(bind_by_move_pattern_guards))]
|
||||||
#![cfg_attr(gate_and_2018, feature(bind_by_move_pattern_guards))]
|
#![cfg_attr(gate_and_2018, feature(bind_by_move_pattern_guards))]
|
||||||
#![cfg_attr(gate_and_znll, feature(bind_by_move_pattern_guards))]
|
|
||||||
#![cfg_attr(gate_and_feature_nll, feature(bind_by_move_pattern_guards))]
|
|
||||||
|
|
||||||
#![cfg_attr(gate_and_feature_nll, feature(nll))]
|
|
||||||
|
|
||||||
//[gate_and_2015] edition:2015
|
//[gate_and_2015] edition:2015
|
||||||
//[gate_and_2018] edition:2018
|
//[gate_and_2018] edition:2018
|
||||||
//[gate_and_znll] compile-flags: -Z borrowck=mir
|
|
||||||
|
|
||||||
struct A { a: Box<i32> }
|
struct A { a: Box<i32> }
|
||||||
|
|
||||||
|
|
@ -43,5 +38,3 @@ fn main() {
|
||||||
}
|
}
|
||||||
//[gate_and_2015]~^^^ ERROR compilation successful
|
//[gate_and_2015]~^^^ ERROR compilation successful
|
||||||
//[gate_and_2018]~^^^^ ERROR compilation successful
|
//[gate_and_2018]~^^^^ ERROR compilation successful
|
||||||
//[gate_and_znll]~^^^^^ ERROR compilation successful
|
|
||||||
//[gate_and_feature_nll]~^^^^^^ ERROR compilation successful
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
// build-pass (FIXME(62277): could be check-pass?)
|
// run-pass
|
||||||
|
|
||||||
struct A { a: Box<i32> }
|
struct A { a: Box<i32> }
|
||||||
|
|
||||||
|
|
@ -8,32 +8,38 @@ impl A {
|
||||||
fn get(&self) -> i32 { *self.a }
|
fn get(&self) -> i32 { *self.a }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(n: i32) {
|
fn foo(n: i32) -> i32 {
|
||||||
let x = A { a: Box::new(n) };
|
let x = A { a: Box::new(n) };
|
||||||
let y = match x {
|
let y = match x {
|
||||||
A { a: v } if *v == 42 => v,
|
A { a: v } if *v == 42 => v,
|
||||||
_ => Box::new(0),
|
_ => Box::new(0),
|
||||||
};
|
};
|
||||||
|
*y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar(n: i32) {
|
fn bar(n: i32) -> i32 {
|
||||||
let x = A { a: Box::new(n) };
|
let x = A { a: Box::new(n) };
|
||||||
let y = match x {
|
let y = match x {
|
||||||
A { a: v } if x.get() == 42 => v,
|
A { a: v } if x.get() == 42 => v,
|
||||||
_ => Box::new(0),
|
_ => Box::new(0),
|
||||||
};
|
};
|
||||||
|
*y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn baz(n: i32) {
|
fn baz(n: i32) -> i32 {
|
||||||
let x = A { a: Box::new(n) };
|
let x = A { a: Box::new(n) };
|
||||||
let y = match x {
|
let y = match x {
|
||||||
A { a: v } if *v.clone() == 42 => v,
|
A { a: v } if *v.clone() == 42 => v,
|
||||||
_ => Box::new(0),
|
_ => Box::new(0),
|
||||||
};
|
};
|
||||||
|
*y
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo(107);
|
assert_eq!(foo(107), 0);
|
||||||
bar(107);
|
assert_eq!(foo(42), 42);
|
||||||
baz(107);
|
assert_eq!(bar(107), 0);
|
||||||
|
assert_eq!(bar(42), 42);
|
||||||
|
assert_eq!(baz(107), 0);
|
||||||
|
assert_eq!(baz(42), 42);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(nll)]
|
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
enum VecWrapper { A(Vec<i32>) }
|
enum VecWrapper { A(Vec<i32>) }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0507]: cannot move out of `v` in pattern guard
|
error[E0507]: cannot move out of `v` in pattern guard
|
||||||
--> $DIR/rfc-reject-double-move-across-arms.rs:8:36
|
--> $DIR/rfc-reject-double-move-across-arms.rs:7:36
|
||||||
|
|
|
|
||||||
LL | VecWrapper::A(v) if { drop(v); false } => 1,
|
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
|
| ^ move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(nll)]
|
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
|
|
||||||
struct A { a: Box<i32> }
|
struct A { a: Box<i32> }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0507]: cannot move out of `v` in pattern guard
|
error[E0507]: cannot move out of `v` in pattern guard
|
||||||
--> $DIR/rfc-reject-double-move-in-first-arm.rs:9:30
|
--> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
|
||||||
|
|
|
|
||||||
LL | A { a: v } if { drop(v); true } => v,
|
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
|
| ^ move occurs because `v` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const TEST_REPOS: &'static [Test] = &[
|
||||||
Test {
|
Test {
|
||||||
name: "servo",
|
name: "servo",
|
||||||
repo: "https://github.com/servo/servo",
|
repo: "https://github.com/servo/servo",
|
||||||
sha: "987e376ca7a4245dbc3e0c06e963278ee1ac92d1",
|
sha: "caac107ae8145ef2fd20365e2b8fadaf09c2eb3b",
|
||||||
lock: None,
|
lock: None,
|
||||||
// Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
|
// Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
|
||||||
// This takes much less time to build than all of Servo and supports stable Rust.
|
// This takes much less time to build than all of Servo and supports stable Rust.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue