Skip to content

Commit eb4f54a

Browse files
committed
let_chains: Move feature gating to pre-expansion.
1 parent d551880 commit eb4f54a

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

src/libsyntax/feature_gate.rs

+11-25
Original file line numberDiff line numberDiff line change
@@ -1940,27 +1940,6 @@ impl<'a> PostExpansionVisitor<'a> {
19401940
Err(mut err) => err.emit(),
19411941
}
19421942
}
1943-
1944-
/// Recurse into all places where a `let` expression would be feature gated
1945-
/// and emit gate post errors for those.
1946-
fn find_and_gate_lets(&mut self, e: &'a ast::Expr) {
1947-
match &e.node {
1948-
ast::ExprKind::Paren(e) => {
1949-
self.find_and_gate_lets(e);
1950-
}
1951-
ast::ExprKind::Binary(op, lhs, rhs) if op.node == ast::BinOpKind::And => {
1952-
self.find_and_gate_lets(lhs);
1953-
self.find_and_gate_lets(rhs);
1954-
}
1955-
ast::ExprKind::Let(..) => {
1956-
gate_feature_post!(
1957-
&self, let_chains, e.span,
1958-
"`let` expressions in this position are experimental"
1959-
);
1960-
}
1961-
_ => {}
1962-
}
1963-
}
19641943
}
19651944

19661945
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@@ -2158,10 +2137,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
21582137

21592138
fn visit_expr(&mut self, e: &'a ast::Expr) {
21602139
match e.node {
2161-
ast::ExprKind::If(ref e, ..) | ast::ExprKind::While(ref e, ..) => match e.node {
2162-
ast::ExprKind::Let(..) => {} // Stable!,
2163-
_ => self.find_and_gate_lets(e),
2164-
}
21652140
ast::ExprKind::Box(_) => {
21662141
gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
21672142
}
@@ -2546,6 +2521,17 @@ pub fn check_crate(krate: &ast::Crate,
25462521
"attributes on function parameters are unstable"
25472522
));
25482523

2524+
sess
2525+
.let_chains_spans
2526+
.borrow()
2527+
.iter()
2528+
.for_each(|span| gate_feature!(
2529+
&ctx,
2530+
let_chains,
2531+
*span,
2532+
"`let` expressions in this position are experimental"
2533+
));
2534+
25492535
let visitor = &mut PostExpansionVisitor {
25502536
context: &ctx,
25512537
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,

src/libsyntax/parse/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ pub struct ParseSess {
5454
/// operation token that followed it, but that the parser cannot identify without further
5555
/// analysis.
5656
pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
57-
pub param_attr_spans: Lock<Vec<Span>>
57+
pub param_attr_spans: Lock<Vec<Span>>,
58+
// Places where `let` exprs were used and should be feature gated according to `let_chains`.
59+
pub let_chains_spans: Lock<Vec<Span>>,
5860
}
5961

6062
impl ParseSess {
@@ -81,6 +83,7 @@ impl ParseSess {
8183
edition: Edition::from_session(),
8284
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
8385
param_attr_spans: Lock::new(Vec::new()),
86+
let_chains_spans: Lock::new(Vec::new()),
8487
}
8588
}
8689

src/libsyntax/parse/parser.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -3158,6 +3158,7 @@ impl<'a> Parser<'a> {
31583158
fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
31593159
let lo = self.prev_span;
31603160
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
3161+
self.ungate_prev_let_expr(&cond);
31613162

31623163
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
31633164
// verify that the last statement is either an implicit return (no `;`) or an explicit
@@ -3187,18 +3188,27 @@ impl<'a> Parser<'a> {
31873188
Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
31883189
}
31893190

3191+
/// Remove the last feature gating of a `let` expression that must the one provided.
3192+
fn ungate_prev_let_expr(&mut self, expr: &Expr) {
3193+
if let ExprKind::Let(..) = expr.node {
3194+
let last = self.sess.let_chains_spans.borrow_mut().pop();
3195+
debug_assert_eq!(expr.span, last.unwrap());
3196+
}
3197+
}
3198+
31903199
/// Parses a `let $pats = $expr` pseudo-expression.
31913200
/// The `let` token has already been eaten.
31923201
fn parse_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
31933202
let lo = self.prev_span;
31943203
let pats = self.parse_pats()?;
31953204
self.expect(&token::Eq)?;
3196-
31973205
let expr = self.with_res(
31983206
Restrictions::NO_STRUCT_LITERAL,
31993207
|this| this.parse_assoc_expr_with(1 + AssocOp::LAnd.precedence(), None.into())
32003208
)?;
3201-
Ok(self.mk_expr(lo.to(expr.span), ExprKind::Let(pats, expr), attrs))
3209+
let span = lo.to(expr.span);
3210+
self.sess.let_chains_spans.borrow_mut().push(span);
3211+
Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs))
32023212
}
32033213

32043214
/// Parses `move |args| expr`.
@@ -3286,6 +3296,7 @@ impl<'a> Parser<'a> {
32863296
span_lo: Span,
32873297
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
32883298
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
3299+
self.ungate_prev_let_expr(&cond);
32893300
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
32903301
attrs.extend(iattrs);
32913302
let span = span_lo.to(body.span);

0 commit comments

Comments
 (0)