Skip to content

Commit

Permalink
Auto merge of rust-lang#74566 - lzutao:guard, r=petrochenkov
Browse files Browse the repository at this point in the history
Gate if-let guard feature

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

Close  rust-lang#74232
cc rust-lang#51114
  • Loading branch information
bors committed Aug 22, 2020
2 parents 527a685 + ef50477 commit 5528caf
Show file tree
Hide file tree
Showing 7 changed files with 453 additions and 3 deletions.
7 changes: 5 additions & 2 deletions src/librustc_ast_passes/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,11 +613,14 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
let spans = sess.parse_sess.gated_spans.spans.borrow();
macro_rules! gate_all {
($gate:ident, $msg:literal) => {
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
gate_feature_post!(&visitor, $gate, *span, $msg);
if let Some(spans) = spans.get(&sym::$gate) {
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!(async_closure, "async closures are unstable");
gate_all!(generators, "yield syntax is experimental");
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,9 @@ declare_features! (
/// The smallest useful subset of `const_generics`.
(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
// -------------------------------------------------------------------------
Expand All @@ -591,6 +594,7 @@ declare_features! (
/// unanticipated results, such as compiler crashes. We warn the user about these
/// to alert them.
pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::if_let_guard,
sym::impl_trait_in_bindings,
sym::generic_associated_types,
sym::const_generics,
Expand Down
14 changes: 13 additions & 1 deletion src/librustc_parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1858,7 +1858,19 @@ impl<'a> Parser<'a> {
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
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;
self.expect(&token::FatArrow)?;
let arm_start_span = self.token.span;
Expand Down
1 change: 1 addition & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ symbols! {
i8,
ident,
if_let,
if_let_guard,
if_while_or_patterns,
ignore,
impl_header_lifetime_elision,
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/parser/struct-literal-in-match-guard.rs
Original file line number Diff line number Diff line change
@@ -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() {}
85 changes: 85 additions & 0 deletions src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Loading

0 comments on commit 5528caf

Please sign in to comment.