Skip to content

Commit 57c5da8

Browse files
committed
Gate to if-let guard feature
1 parent d19d7e2 commit 57c5da8

File tree

8 files changed

+440
-30
lines changed

8 files changed

+440
-30
lines changed

src/librustc_ast_passes/feature_gate.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -612,11 +612,14 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
612612
let spans = sess.parse_sess.gated_spans.spans.borrow();
613613
macro_rules! gate_all {
614614
($gate:ident, $msg:literal) => {
615-
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
616-
gate_feature_post!(&visitor, $gate, *span, $msg);
615+
if let Some(spans) = spans.get(&sym::$gate) {
616+
for span in spans {
617+
gate_feature_post!(&visitor, $gate, *span, $msg);
618+
}
617619
}
618620
};
619621
}
622+
gate_all!(if_let_guard, "`if let` guard is not implemented");
620623
gate_all!(let_chains, "`let` expressions in this position are experimental");
621624
gate_all!(async_closure, "async closures are unstable");
622625
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.46.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
@@ -1821,7 +1821,19 @@ impl<'a> Parser<'a> {
18211821
let attrs = self.parse_outer_attributes()?;
18221822
let lo = self.token.span;
18231823
let pat = self.parse_top_pat(GateOr::No)?;
1824-
let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { None };
1824+
let guard = if self.eat_keyword(kw::If) {
1825+
let if_span = self.prev_token.span;
1826+
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
1827+
if let ExprKind::Let(..) = cond.kind {
1828+
// Remove the last feature gating of a `let` expression since it's stable.
1829+
self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
1830+
let span = if_span.to(cond.span);
1831+
self.sess.gated_spans.gate(sym::if_let_guard, span);
1832+
}
1833+
Some(cond)
1834+
} else {
1835+
None
1836+
};
18251837
let arrow_span = self.token.span;
18261838
self.expect(&token::FatArrow)?;
18271839
let arm_start_span = self.token.span;

src/librustc_span/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ symbols! {
572572
i8,
573573
ident,
574574
if_let,
575+
if_let_guard,
575576
if_while_or_patterns,
576577
ignore,
577578
impl_header_lifetime_elision,

src/test/ui/parser/issue-15980.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@ fn main(){
44
let x: io::Result<()> = Ok(());
55
match x {
66
Err(ref e) if e.kind == io::EndOfFile {
7-
//~^ NOTE while parsing this struct
7+
//~^ ERROR expected one of `!`, `.`, `::`, `=>`, `?`, or an operator, found `{`
88
return
9-
//~^ ERROR expected identifier, found keyword `return`
10-
//~| NOTE expected identifier, found keyword
119
}
12-
//~^ NOTE expected one of `.`, `=>`, `?`, or an operator
1310
_ => {}
14-
//~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
15-
//~| NOTE unexpected token
1611
}
1712
}

src/test/ui/parser/issue-15980.stderr

+4-21
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,8 @@
1-
error: expected identifier, found keyword `return`
2-
--> $DIR/issue-15980.rs:8:13
1+
error: expected one of `!`, `.`, `::`, `=>`, `?`, or an operator, found `{`
2+
--> $DIR/issue-15980.rs:6:47
33
|
44
LL | Err(ref e) if e.kind == io::EndOfFile {
5-
| ------------- while parsing this struct
6-
LL |
7-
LL | return
8-
| ^^^^^^ expected identifier, found keyword
9-
|
10-
help: you can escape reserved keywords to use them as identifiers
11-
|
12-
LL | r#return
13-
|
14-
15-
error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
16-
--> $DIR/issue-15980.rs:13:9
17-
|
18-
LL | }
19-
| - expected one of `.`, `=>`, `?`, or an operator
20-
LL |
21-
LL | _ => {}
22-
| ^ unexpected token
5+
| ^ expected one of `!`, `.`, `::`, `=>`, `?`, or an operator
236

24-
error: aborting due to 2 previous errors
7+
error: aborting due to previous error
258

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)