Skip to content

Commit 5528caf

Browse files
committed
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
2 parents 527a685 + ef50477 commit 5528caf

File tree

7 files changed

+453
-3
lines changed

7 files changed

+453
-3
lines changed

src/librustc_ast_passes/feature_gate.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -613,11 +613,14 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
613613
let spans = sess.parse_sess.gated_spans.spans.borrow();
614614
macro_rules! gate_all {
615615
($gate:ident, $msg:literal) => {
616-
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
617-
gate_feature_post!(&visitor, $gate, *span, $msg);
616+
if let Some(spans) = spans.get(&sym::$gate) {
617+
for span in spans {
618+
gate_feature_post!(&visitor, $gate, *span, $msg);
619+
}
618620
}
619621
};
620622
}
623+
gate_all!(if_let_guard, "`if let` guard is not implemented");
621624
gate_all!(let_chains, "`let` expressions in this position are experimental");
622625
gate_all!(async_closure, "async closures are unstable");
623626
gate_all!(generators, "yield syntax is experimental");

src/librustc_feature/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ declare_features! (
582582
/// The smallest useful subset of `const_generics`.
583583
(active, min_const_generics, "1.47.0", Some(74878), None),
584584

585+
/// Allows `if let` guard in match arms.
586+
(active, if_let_guard, "1.47.0", Some(51114), None),
587+
585588
// -------------------------------------------------------------------------
586589
// feature-group-end: actual feature gates
587590
// -------------------------------------------------------------------------
@@ -591,6 +594,7 @@ declare_features! (
591594
/// unanticipated results, such as compiler crashes. We warn the user about these
592595
/// to alert them.
593596
pub const INCOMPLETE_FEATURES: &[Symbol] = &[
597+
sym::if_let_guard,
594598
sym::impl_trait_in_bindings,
595599
sym::generic_associated_types,
596600
sym::const_generics,

src/librustc_parse/parser/expr.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -1858,7 +1858,19 @@ impl<'a> Parser<'a> {
18581858
let attrs = self.parse_outer_attributes()?;
18591859
let lo = self.token.span;
18601860
let pat = self.parse_top_pat(GateOr::No)?;
1861-
let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { None };
1861+
let guard = if self.eat_keyword(kw::If) {
1862+
let if_span = self.prev_token.span;
1863+
let cond = self.parse_expr()?;
1864+
if let ExprKind::Let(..) = cond.kind {
1865+
// Remove the last feature gating of a `let` expression since it's stable.
1866+
self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
1867+
let span = if_span.to(cond.span);
1868+
self.sess.gated_spans.gate(sym::if_let_guard, span);
1869+
}
1870+
Some(cond)
1871+
} else {
1872+
None
1873+
};
18621874
let arrow_span = self.token.span;
18631875
self.expect(&token::FatArrow)?;
18641876
let arm_start_span = self.token.span;

src/librustc_span/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ symbols! {
567567
i8,
568568
ident,
569569
if_let,
570+
if_let_guard,
570571
if_while_or_patterns,
571572
ignore,
572573
impl_header_lifetime_elision,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// check-pass
2+
3+
// Unlike `if` condition, `match` guards accept struct literals.
4+
// This is detected in <https://github.com/rust-lang/rust/pull/74566#issuecomment-663613705>.
5+
6+
#[derive(PartialEq)]
7+
struct Foo {
8+
x: isize,
9+
}
10+
11+
fn foo(f: Foo) {
12+
match () {
13+
() if f == Foo { x: 42 } => {}
14+
_ => {}
15+
}
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// gate-test-if_let_guard
2+
3+
use std::ops::Range;
4+
5+
fn _if_let_guard() {
6+
match () {
7+
() if let 0 = 1 => {}
8+
//~^ ERROR `if let` guard is not implemented
9+
//~| ERROR `let` expressions are not supported here
10+
11+
() if (let 0 = 1) => {}
12+
//~^ ERROR `let` expressions in this position are experimental
13+
//~| ERROR `let` expressions are not supported here
14+
15+
() if (((let 0 = 1))) => {}
16+
//~^ ERROR `let` expressions in this position are experimental
17+
//~| ERROR `let` expressions are not supported here
18+
19+
() if true && let 0 = 1 => {}
20+
//~^ ERROR `let` expressions in this position are experimental
21+
//~| ERROR `let` expressions are not supported here
22+
23+
() if let 0 = 1 && true => {}
24+
//~^ ERROR `let` expressions in this position are experimental
25+
//~| ERROR `let` expressions are not supported here
26+
27+
() if (let 0 = 1) && true => {}
28+
//~^ ERROR `let` expressions in this position are experimental
29+
//~| ERROR `let` expressions are not supported here
30+
31+
() if true && (let 0 = 1) => {}
32+
//~^ ERROR `let` expressions in this position are experimental
33+
//~| ERROR `let` expressions are not supported here
34+
35+
() if (let 0 = 1) && (let 0 = 1) => {}
36+
//~^ ERROR `let` expressions in this position are experimental
37+
//~| ERROR `let` expressions in this position are experimental
38+
//~| ERROR `let` expressions are not supported here
39+
//~| ERROR `let` expressions are not supported here
40+
41+
() if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
42+
//~^ ERROR `let` expressions in this position are experimental
43+
//~| ERROR `let` expressions in this position are experimental
44+
//~| ERROR `let` expressions in this position are experimental
45+
//~| ERROR `let` expressions in this position are experimental
46+
//~| ERROR `let` expressions in this position are experimental
47+
//~| ERROR `let` expressions are not supported here
48+
//~| ERROR `let` expressions are not supported here
49+
//~| ERROR `let` expressions are not supported here
50+
//~| ERROR `let` expressions are not supported here
51+
//~| ERROR `let` expressions are not supported here
52+
53+
() if let Range { start: _, end: _ } = (true..true) && false => {}
54+
//~^ ERROR `let` expressions in this position are experimental
55+
//~| ERROR `let` expressions are not supported here
56+
_ => {}
57+
}
58+
}
59+
60+
fn _macros() {
61+
macro_rules! use_expr {
62+
($e:expr) => {
63+
match () {
64+
() if $e => {}
65+
_ => {}
66+
}
67+
}
68+
}
69+
use_expr!((let 0 = 1 && 0 == 0));
70+
//~^ ERROR `let` expressions in this position are experimental
71+
//~| ERROR `let` expressions are not supported here
72+
use_expr!((let 0 = 1));
73+
//~^ ERROR `let` expressions in this position are experimental
74+
//~| ERROR `let` expressions are not supported here
75+
match () {
76+
#[cfg(FALSE)]
77+
() if let 0 = 1 => {}
78+
//~^ ERROR `if let` guard is not implemented
79+
_ => {}
80+
}
81+
use_expr!(let 0 = 1);
82+
//~^ ERROR no rules expected the token `let`
83+
}
84+
85+
fn main() {}

0 commit comments

Comments
 (0)