mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
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
@ -461,7 +461,7 @@ rustc_queries! {
|
||||
}
|
||||
|
||||
TypeChecking {
|
||||
query check_match(key: DefId) -> () {
|
||||
query check_match(key: DefId) -> SignalledError {
|
||||
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::infer::canonical::{self, Canonical};
|
||||
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::{NativeLibraryKind, DepKind, CrateSource};
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
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:
|
||||
|
||||
```compile_fail,E0510
|
||||
#![feature(nll, bind_by_move_pattern_guards)]
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
let mut x = Some(0);
|
||||
match x {
|
||||
None => (),
|
||||
|
@ -4,6 +4,7 @@ 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;
|
||||
@ -26,21 +27,24 @@ use std::slice;
|
||||
|
||||
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) {
|
||||
tcx.hir().body_owned_by(id)
|
||||
} else {
|
||||
return;
|
||||
return SignalledError::NoErrorsSeen;
|
||||
};
|
||||
|
||||
MatchVisitor {
|
||||
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),
|
||||
}.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<'_> {
|
||||
@ -54,6 +58,7 @@ struct MatchVisitor<'a, 'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
identity_substs: SubstsRef<'tcx>,
|
||||
region_scope_tree: &'a region::ScopeTree,
|
||||
signalled_error: SignalledError,
|
||||
}
|
||||
|
||||
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) {
|
||||
intravisit::walk_expr(self, ex);
|
||||
|
||||
match ex.node {
|
||||
hir::ExprKind::Match(ref scrut, ref arms, source) => {
|
||||
self.check_match(scrut, arms, source);
|
||||
}
|
||||
_ => {}
|
||||
if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.node {
|
||||
self.check_match(scrut, arms, source);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +132,7 @@ impl<'a, 'tcx> PatternContext<'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);
|
||||
for pat in pats {
|
||||
check_legality_of_bindings_in_at_patterns(self, pat);
|
||||
@ -138,11 +140,11 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn check_match(
|
||||
&self,
|
||||
&mut self,
|
||||
scrut: &hir::Expr,
|
||||
arms: &'tcx [hir::Arm],
|
||||
source: hir::MatchSource)
|
||||
{
|
||||
source: hir::MatchSource
|
||||
) {
|
||||
for arm in arms {
|
||||
// First, check legality of move bindings.
|
||||
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
|
||||
// assigning or borrowing anything mutably.
|
||||
if let Some(ref guard) = arm.guard {
|
||||
self.signalled_error = SignalledError::SawSomeError;
|
||||
if !self.tcx.features().bind_by_move_pattern_guards {
|
||||
check_for_mutation_in_guard(self, &guard);
|
||||
}
|
||||
@ -548,7 +551,7 @@ fn maybe_point_at_variant(
|
||||
|
||||
// Legality of move bindings checking
|
||||
fn check_legality_of_move_bindings(
|
||||
cx: &MatchVisitor<'_, '_>,
|
||||
cx: &mut MatchVisitor<'_, '_>,
|
||||
has_guard: bool,
|
||||
pats: &[P<Pat>],
|
||||
) {
|
||||
@ -565,7 +568,12 @@ fn check_legality_of_move_bindings(
|
||||
})
|
||||
}
|
||||
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
|
||||
|
||||
// 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")
|
||||
.span_label(p.span, "binds an already bound by-move value by moving it")
|
||||
.emit();
|
||||
} else if has_guard && !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");
|
||||
} 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();
|
||||
}
|
||||
err.emit();
|
||||
} else if let Some(_by_ref_span) = by_ref_span {
|
||||
span_vec.push(p.span);
|
||||
}
|
||||
@ -596,7 +606,7 @@ fn check_legality_of_move_bindings(
|
||||
ty::BindByValue(..) => {
|
||||
let pat_ty = cx.tables.node_type(p.hir_id);
|
||||
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
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:26:18
|
||||
warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:28:21
|
||||
|
|
||||
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
|
||||
LL | let x = &mut block;
|
||||
| ---------- mutable borrow occurs here
|
||||
LL | let p: &'a u8 = &*block.current;
|
||||
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
|
||||
LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes)
|
||||
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 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`
|
||||
|
@ -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
|
||||
// AST-borrowck, but is correctly rejected by the NLL borrowck.
|
||||
//
|
||||
@ -18,15 +18,17 @@
|
||||
//[zflag] run-pass
|
||||
//[edition] run-pass
|
||||
|
||||
fn main() {
|
||||
match Some(&4) {
|
||||
None => {},
|
||||
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."),
|
||||
}
|
||||
pub struct Block<'a> {
|
||||
current: &'a u8,
|
||||
unrelated: &'a u8,
|
||||
}
|
||||
|
||||
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
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:26:18
|
||||
warning[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-migrate-to-nll.rs:28:21
|
||||
|
|
||||
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
|
||||
LL | let x = &mut block;
|
||||
| ---------- mutable borrow occurs here
|
||||
LL | let p: &'a u8 = &*block.current;
|
||||
| ^^^^^^^^^^^^^^^ immutable borrow occurs here
|
||||
LL | // (use `x` and `p` so enabling NLL doesn't assign overly short lifetimes)
|
||||
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 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`
|
||||
|
@ -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 {
|
||||
Enum::A(_) if { x = Enum::B(false); false } => 1,
|
||||
//~^ ERROR cannot assign in a pattern guard
|
||||
//~| WARN 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
|
||||
//~| 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
|
||||
//~| WARN 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
|
||||
//~| ERROR cannot mutably borrow `x` in match guard
|
||||
Enum::A(p) => *p,
|
||||
Enum::B(_) => 2,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ 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
|
||||
--> $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
|
||||
@ -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
|
||||
|
||||
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,
|
||||
| ^^^^^^^^^^^^^^^^^^^ 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
|
||||
|
|
||||
LL | match x {
|
||||
| - value is immutable in match guard
|
||||
LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
|
||||
| ^^^^^^^^^^^^^^^^^^ 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
|
||||
--> $DIR/borrowck-mutate-in-guard.rs:15:33
|
||||
error[E0510]: cannot mutably borrow `x` in match guard
|
||||
--> $DIR/borrowck-mutate-in-guard.rs:13: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
|
||||
|
|
||||
= 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.
|
||||
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
|
||||
// (under NLL) even when that conservaive check goes away.
|
||||
|
||||
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
#![feature(nll)]
|
||||
|
||||
fn main() {
|
||||
let mut b = &mut true;
|
||||
|
@ -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:16:25
|
||||
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
|
||||
|
|
||||
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
|
||||
| ^^ - mutable borrow occurs due to use of `r` in closure
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
// run-pass
|
||||
|
||||
#![feature(nll, bind_by_move_pattern_guards)]
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
// Test that z always point to the same temporary.
|
||||
fn referent_stability() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Test that we have enough false edges to avoid exposing the exact matching
|
||||
// algorithm in borrow checking.
|
||||
|
||||
#![feature(nll, bind_by_move_pattern_guards)]
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
fn guard_always_precedes_arm(y: i32) {
|
||||
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() {}
|
||||
|
@ -16,19 +16,7 @@ LL | true => {
|
||||
LL | x;
|
||||
| ^ value used here after move
|
||||
|
||||
error[E0503]: cannot use `y.1` because it was mutably borrowed
|
||||
--> $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 2 previous errors
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0381, E0382, E0503.
|
||||
Some errors have detailed explanations: E0381, E0382.
|
||||
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
|
||||
// changes which patterns it matches, until we have chosen an arm.
|
||||
|
||||
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
#![feature(nll)]
|
||||
|
||||
fn ok_mutation_in_guard(mut q: i32) {
|
||||
match q {
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 {
|
||||
| - 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:71:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:69: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:95:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:93: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:109:22
|
||||
--> $DIR/match-guards-partially-borrow.rs:107: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:121:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:119: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:132:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:130: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:143:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:141: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:155:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:153: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:166:13
|
||||
--> $DIR/match-guards-partially-borrow.rs:164:13
|
||||
|
|
||||
LL | match b {
|
||||
| - value is immutable in match guard
|
||||
|
@ -2,7 +2,7 @@
|
||||
// rust-lang/rust#2329), that starts passing with this feature in
|
||||
// place.
|
||||
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// run-pass
|
||||
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
|
||||
@ -12,6 +12,7 @@ fn main() {
|
||||
let (tx, rx) = channel();
|
||||
let x = Some(rx);
|
||||
tx.send(false);
|
||||
tx.send(false);
|
||||
match x {
|
||||
Some(z) if z.recv().unwrap() => { panic!() },
|
||||
Some(z) => { assert!(!z.recv().unwrap()); },
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: compilation successful
|
||||
--> $DIR/feature-gate.rs:41:1
|
||||
--> $DIR/feature-gate.rs:36:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | foo(107)
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: compilation successful
|
||||
--> $DIR/feature-gate.rs:41:1
|
||||
--> $DIR/feature-gate.rs:36:1
|
||||
|
|
||||
LL | / fn main() {
|
||||
LL | | foo(107)
|
||||
|
@ -1,5 +1,5 @@
|
||||
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,
|
||||
| ^ moves value into pattern guard
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
// 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.)
|
||||
// ignore-compare-mode-nll
|
||||
@ -15,14 +15,9 @@
|
||||
|
||||
#![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_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_2018] edition:2018
|
||||
//[gate_and_znll] compile-flags: -Z borrowck=mir
|
||||
|
||||
struct A { a: Box<i32> }
|
||||
|
||||
@ -43,5 +38,3 @@ fn main() {
|
||||
}
|
||||
//[gate_and_2015]~^^^ 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)]
|
||||
|
||||
// build-pass (FIXME(62277): could be check-pass?)
|
||||
// run-pass
|
||||
|
||||
struct A { a: Box<i32> }
|
||||
|
||||
@ -8,32 +8,38 @@ impl A {
|
||||
fn get(&self) -> i32 { *self.a }
|
||||
}
|
||||
|
||||
fn foo(n: i32) {
|
||||
fn foo(n: i32) -> i32 {
|
||||
let x = A { a: Box::new(n) };
|
||||
let y = match x {
|
||||
A { a: v } if *v == 42 => v,
|
||||
_ => Box::new(0),
|
||||
};
|
||||
*y
|
||||
}
|
||||
|
||||
fn bar(n: i32) {
|
||||
fn bar(n: i32) -> i32 {
|
||||
let x = A { a: Box::new(n) };
|
||||
let y = match x {
|
||||
A { a: v } if x.get() == 42 => v,
|
||||
_ => Box::new(0),
|
||||
};
|
||||
*y
|
||||
}
|
||||
|
||||
fn baz(n: i32) {
|
||||
fn baz(n: i32) -> i32 {
|
||||
let x = A { a: Box::new(n) };
|
||||
let y = match x {
|
||||
A { a: v } if *v.clone() == 42 => v,
|
||||
_ => Box::new(0),
|
||||
};
|
||||
*y
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo(107);
|
||||
bar(107);
|
||||
baz(107);
|
||||
assert_eq!(foo(107), 0);
|
||||
assert_eq!(foo(42), 42);
|
||||
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)]
|
||||
|
||||
enum VecWrapper { A(Vec<i32>) }
|
||||
|
@ -1,5 +1,5 @@
|
||||
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,
|
||||
| ^ 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)]
|
||||
|
||||
struct A { a: Box<i32> }
|
||||
|
@ -1,5 +1,5 @@
|
||||
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,
|
||||
| ^ 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 {
|
||||
name: "servo",
|
||||
repo: "https://github.com/servo/servo",
|
||||
sha: "987e376ca7a4245dbc3e0c06e963278ee1ac92d1",
|
||||
sha: "caac107ae8145ef2fd20365e2b8fadaf09c2eb3b",
|
||||
lock: None,
|
||||
// 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.
|
||||
|
Loading…
Reference in New Issue
Block a user