Auto merge of #74566 - lzutao:guard, r=petrochenkov

Gate if-let guard feature

Enhanced on #74315. That PR is in crater queue so I don't want to push to it.

Close  #74232
cc #51114
This commit is contained in:
bors 2020-08-22 15:38:13 +00:00
commit 5528caf914
7 changed files with 453 additions and 3 deletions

View File

@ -613,11 +613,14 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
let spans = sess.parse_sess.gated_spans.spans.borrow(); let spans = sess.parse_sess.gated_spans.spans.borrow();
macro_rules! gate_all { macro_rules! gate_all {
($gate:ident, $msg:literal) => { ($gate:ident, $msg:literal) => {
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { if let Some(spans) = spans.get(&sym::$gate) {
gate_feature_post!(&visitor, $gate, *span, $msg); for span in spans {
gate_feature_post!(&visitor, $gate, *span, $msg);
}
} }
}; };
} }
gate_all!(if_let_guard, "`if let` guard is not implemented");
gate_all!(let_chains, "`let` expressions in this position are experimental"); gate_all!(let_chains, "`let` expressions in this position are experimental");
gate_all!(async_closure, "async closures are unstable"); gate_all!(async_closure, "async closures are unstable");
gate_all!(generators, "yield syntax is experimental"); gate_all!(generators, "yield syntax is experimental");

View File

@ -582,6 +582,9 @@ declare_features! (
/// The smallest useful subset of `const_generics`. /// The smallest useful subset of `const_generics`.
(active, min_const_generics, "1.47.0", Some(74878), None), (active, min_const_generics, "1.47.0", Some(74878), None),
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// feature-group-end: actual feature gates // feature-group-end: actual feature gates
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -591,6 +594,7 @@ declare_features! (
/// unanticipated results, such as compiler crashes. We warn the user about these /// unanticipated results, such as compiler crashes. We warn the user about these
/// to alert them. /// to alert them.
pub const INCOMPLETE_FEATURES: &[Symbol] = &[ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::if_let_guard,
sym::impl_trait_in_bindings, sym::impl_trait_in_bindings,
sym::generic_associated_types, sym::generic_associated_types,
sym::const_generics, sym::const_generics,

View File

@ -1858,7 +1858,19 @@ impl<'a> Parser<'a> {
let attrs = self.parse_outer_attributes()?; let attrs = self.parse_outer_attributes()?;
let lo = self.token.span; let lo = self.token.span;
let pat = self.parse_top_pat(GateOr::No)?; let pat = self.parse_top_pat(GateOr::No)?;
let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { None }; let guard = if self.eat_keyword(kw::If) {
let if_span = self.prev_token.span;
let cond = self.parse_expr()?;
if let ExprKind::Let(..) = cond.kind {
// Remove the last feature gating of a `let` expression since it's stable.
self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
let span = if_span.to(cond.span);
self.sess.gated_spans.gate(sym::if_let_guard, span);
}
Some(cond)
} else {
None
};
let arrow_span = self.token.span; let arrow_span = self.token.span;
self.expect(&token::FatArrow)?; self.expect(&token::FatArrow)?;
let arm_start_span = self.token.span; let arm_start_span = self.token.span;

View File

@ -567,6 +567,7 @@ symbols! {
i8, i8,
ident, ident,
if_let, if_let,
if_let_guard,
if_while_or_patterns, if_while_or_patterns,
ignore, ignore,
impl_header_lifetime_elision, impl_header_lifetime_elision,

View File

@ -0,0 +1,18 @@
// check-pass
// Unlike `if` condition, `match` guards accept struct literals.
// This is detected in <https://github.com/rust-lang/rust/pull/74566#issuecomment-663613705>.
#[derive(PartialEq)]
struct Foo {
x: isize,
}
fn foo(f: Foo) {
match () {
() if f == Foo { x: 42 } => {}
_ => {}
}
}
fn main() {}

View File

@ -0,0 +1,85 @@
// gate-test-if_let_guard
use std::ops::Range;
fn _if_let_guard() {
match () {
() if let 0 = 1 => {}
//~^ ERROR `if let` guard is not implemented
//~| ERROR `let` expressions are not supported here
() if (let 0 = 1) => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
() if (((let 0 = 1))) => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
() if true && let 0 = 1 => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
() if let 0 = 1 && true => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
() if (let 0 = 1) && true => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
() if true && (let 0 = 1) => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
() if (let 0 = 1) && (let 0 = 1) => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
() if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
() if let Range { start: _, end: _ } = (true..true) && false => {}
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
_ => {}
}
}
fn _macros() {
macro_rules! use_expr {
($e:expr) => {
match () {
() if $e => {}
_ => {}
}
}
}
use_expr!((let 0 = 1 && 0 == 0));
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
use_expr!((let 0 = 1));
//~^ ERROR `let` expressions in this position are experimental
//~| ERROR `let` expressions are not supported here
match () {
#[cfg(FALSE)]
() if let 0 = 1 => {}
//~^ ERROR `if let` guard is not implemented
_ => {}
}
use_expr!(let 0 = 1);
//~^ ERROR no rules expected the token `let`
}
fn main() {}

View File

@ -0,0 +1,327 @@
error: no rules expected the token `let`
--> $DIR/feature-gate.rs:81:15
|
LL | macro_rules! use_expr {
| --------------------- when calling this macro
...
LL | use_expr!(let 0 = 1);
| ^^^ no rules expected this token in macro call
error[E0658]: `if let` guard is not implemented
--> $DIR/feature-gate.rs:7:12
|
LL | () if let 0 = 1 => {}
| ^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
error[E0658]: `if let` guard is not implemented
--> $DIR/feature-gate.rs:77:12
|
LL | () if let 0 = 1 => {}
| ^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:11:16
|
LL | () if (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:15:18
|
LL | () if (((let 0 = 1))) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:19:23
|
LL | () if true && let 0 = 1 => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:23:15
|
LL | () if let 0 = 1 && true => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:27:16
|
LL | () if (let 0 = 1) && true => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:31:24
|
LL | () if true && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:35:16
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:35:31
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:41:15
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:41:28
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:41:42
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:41:55
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:41:68
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:53:15
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:69:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are experimental
--> $DIR/feature-gate.rs:72:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:7:15
|
LL | () if let 0 = 1 => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:11:16
|
LL | () if (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:15:18
|
LL | () if (((let 0 = 1))) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:19:23
|
LL | () if true && let 0 = 1 => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:23:15
|
LL | () if let 0 = 1 && true => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:27:16
|
LL | () if (let 0 = 1) && true => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:31:24
|
LL | () if true && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:35:16
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:35:31
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:41:15
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:41:28
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:41:42
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:41:55
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:41:68
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:53:15
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:69:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: `let` expressions are not supported here
--> $DIR/feature-gate.rs:72:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
= note: as well as when nested within `&&` and parenthesis in those conditions
error: aborting due to 36 previous errors
For more information about this error, try `rustc --explain E0658`.