Skip to content

Commit 79fcc58

Browse files
committed
Auto merge of rust-lang#54034 - pnkfelix:issue-15287-bind-by-move-pattern-guards, r=nikomatsakis
Add feature to enable bind by move pattern guards Implement rust-lang#15287 as described on rust-lang#15287 (comment)
2 parents f004cae + 3a07d3d commit 79fcc58

21 files changed

+318
-21
lines changed

src/librustc/ty/context.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1448,10 +1448,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
14481448
self.queries.on_disk_cache.serialize(self.global_tcx(), encoder)
14491449
}
14501450

1451+
/// This checks whether one is allowed to have pattern bindings
1452+
/// that bind-by-move on a match arm that has a guard, e.g.:
1453+
///
1454+
/// ```rust
1455+
/// match foo { A(inner) if { /* something */ } => ..., ... }
1456+
/// ```
1457+
///
1458+
/// It is separate from check_for_mutation_in_guard_via_ast_walk,
1459+
/// because that method has a narrower effect that can be toggled
1460+
/// off via a separate `-Z` flag, at least for the short term.
1461+
pub fn allow_bind_by_move_patterns_with_guards(self) -> bool {
1462+
self.features().bind_by_move_pattern_guards && self.use_mir_borrowck()
1463+
}
1464+
14511465
/// If true, we should use a naive AST walk to determine if match
14521466
/// guard could perform bad mutations (or mutable-borrows).
14531467
pub fn check_for_mutation_in_guard_via_ast_walk(self) -> bool {
1454-
!self.sess.opts.debugging_opts.disable_ast_check_for_mutation_in_guard
1468+
// If someone passes the `-Z` flag, they're asking for the footgun.
1469+
if self.sess.opts.debugging_opts.disable_ast_check_for_mutation_in_guard {
1470+
return false;
1471+
}
1472+
1473+
// If someone requests the feature, then be a little more
1474+
// careful and ensure that MIR-borrowck is enabled (which can
1475+
// happen via edition selection, via `feature(nll)`, or via an
1476+
// appropriate `-Z` flag) before disabling the mutation check.
1477+
if self.allow_bind_by_move_patterns_with_guards() {
1478+
return false;
1479+
}
1480+
1481+
return true;
14551482
}
14561483

14571484
/// If true, we should use the AST-based borrowck (we may *also* use

src/librustc_mir/hair/pattern/check_match.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -537,11 +537,15 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
537537
"cannot bind by-move with sub-bindings")
538538
.span_label(p.span, "binds an already bound by-move value by moving it")
539539
.emit();
540-
} else if has_guard {
541-
struct_span_err!(cx.tcx.sess, p.span, E0008,
542-
"cannot bind by-move into a pattern guard")
543-
.span_label(p.span, "moves value into pattern guard")
544-
.emit();
540+
} else if has_guard && !cx.tcx.allow_bind_by_move_patterns_with_guards() {
541+
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
542+
"cannot bind by-move into a pattern guard");
543+
err.span_label(p.span, "moves value into pattern guard");
544+
if cx.tcx.sess.opts.unstable_features.is_nightly_build() && cx.tcx.use_mir_borrowck() {
545+
err.help("add #![feature(bind_by_move_pattern_guards)] to the \
546+
crate attributes to enable");
547+
}
548+
err.emit();
545549
} else if let Some(by_ref_span) = by_ref_span {
546550
struct_span_err!(
547551
cx.tcx.sess,
@@ -613,10 +617,16 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
613617
_: LoanCause) {
614618
match kind {
615619
ty::MutBorrow => {
616-
struct_span_err!(self.cx.tcx.sess, span, E0301,
617-
"cannot mutably borrow in a pattern guard")
618-
.span_label(span, "borrowed mutably in pattern guard")
619-
.emit();
620+
let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301,
621+
"cannot mutably borrow in a pattern guard");
622+
err.span_label(span, "borrowed mutably in pattern guard");
623+
if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() &&
624+
self.cx.tcx.use_mir_borrowck()
625+
{
626+
err.help("add #![feature(bind_by_move_pattern_guards)] to the \
627+
crate attributes to enable");
628+
}
629+
err.emit();
620630
}
621631
ty::ImmBorrow | ty::UniqueImmBorrow => {}
622632
}

src/libsyntax/feature_gate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,12 @@ declare_features! (
515515

516516
// Self struct constructor (RFC 2302)
517517
(active, self_struct_ctor, "1.31.0", Some(51994), None),
518+
519+
// allow mixing of bind-by-move in patterns and references to
520+
// those identifiers in guards, *if* we are using MIR-borrowck
521+
// (aka NLL). Essentially this means you need to be on
522+
// edition:2018 or later.
523+
(active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
518524
);
519525

520526
declare_features! (
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0008]: cannot bind by-move into a pattern guard
2+
--> $DIR/bind-by-move-no-guards.rs:8:14
3+
|
4+
LL | Some(z) if z.recv().unwrap() => { panic!() },
5+
| ^ moves value into pattern guard
6+
|
7+
= help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0008`.

src/test/ui/bind-by-move/bind-by-move-no-guards.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2-
// file at the top-level directory of this distribution and at
3-
// http://rust-lang.org/COPYRIGHT.
4-
//
5-
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6-
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7-
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8-
// option. This file may not be copied, modified, or distributed
9-
// except according to those terms.
10-
111
use std::sync::mpsc::channel;
122

133
fn main() {

src/test/ui/bind-by-move/bind-by-move-no-guards.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0008]: cannot bind by-move into a pattern guard
2-
--> $DIR/bind-by-move-no-guards.rs:18:14
2+
--> $DIR/bind-by-move-no-guards.rs:8:14
33
|
44
LL | Some(z) if z.recv().unwrap() => { panic!() },
55
| ^ moves value into pattern guard
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0302]: cannot assign in a pattern guard
2+
--> $DIR/borrowck-mutate-in-guard.rs:20:25
3+
|
4+
LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
5+
| ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
6+
7+
error[E0301]: cannot mutably borrow in a pattern guard
8+
--> $DIR/borrowck-mutate-in-guard.rs:22:38
9+
|
10+
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
11+
| ^ borrowed mutably in pattern guard
12+
|
13+
= help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
14+
15+
error[E0302]: cannot assign in a pattern guard
16+
--> $DIR/borrowck-mutate-in-guard.rs:22:41
17+
|
18+
LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
19+
| ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
20+
21+
error: aborting due to 3 previous errors
22+
23+
Some errors occurred: E0301, E0302.
24+
For more information about an error, try `rustc --explain E0301`.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0008]: cannot bind by-move into a pattern guard
2+
--> $DIR/E0008.rs:13:14
3+
|
4+
LL | Some(s) if s.len() == 0 => {},
5+
| ^ moves value into pattern guard
6+
|
7+
= help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0008`.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0301]: cannot mutably borrow in a pattern guard
2+
--> $DIR/E0301.rs:14:19
3+
|
4+
LL | option if option.take().is_none() => {}, //~ ERROR E0301
5+
| ^^^^^^ borrowed mutably in pattern guard
6+
|
7+
= help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0301`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Adaptation of existing ui test (from way back in
2+
// rust-lang/rust#2329), that starts passing with this feature in
3+
// place.
4+
5+
// compile-pass
6+
7+
#![feature(nll)]
8+
#![feature(bind_by_move_pattern_guards)]
9+
10+
use std::sync::mpsc::channel;
11+
12+
fn main() {
13+
let (tx, rx) = channel();
14+
let x = Some(rx);
15+
tx.send(false);
16+
match x {
17+
Some(z) if z.recv().unwrap() => { panic!() },
18+
Some(z) => { assert!(!z.recv().unwrap()); },
19+
None => panic!()
20+
}
21+
}

0 commit comments

Comments
 (0)