Skip to content

Commit a80aa34

Browse files
committed
let_chains: Change AST validation strategy slightly.
1 parent 1ff947f commit a80aa34

File tree

1 file changed

+45
-34
lines changed

1 file changed

+45
-34
lines changed

src/librustc_passes/ast_validation.rs

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ impl<'a> AstValidator<'a> {
114114
with(self, outer, |this| &mut this.outer_impl_trait, f)
115115
}
116116

117-
fn with_let_allowed(&mut self, v: bool, f: impl FnOnce(&mut Self)) {
118-
with(self, v, |this| &mut this.is_let_allowed, f)
117+
fn with_let_allowed(&mut self, v: bool, f: impl FnOnce(&mut Self, bool)) {
118+
let old = mem::replace(&mut self.is_let_allowed, v);
119+
f(self, old);
120+
self.is_let_allowed = old;
119121
}
120122

121123
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
@@ -336,27 +338,29 @@ impl<'a> AstValidator<'a> {
336338
/// Visits the `expr` and adjusts whether `let $pat = $expr` is allowed in decendants.
337339
/// Returns whether we walked into `expr` or not.
338340
/// If we did, walking should not happen again.
339-
fn visit_expr_with_let_maybe_allowed(&mut self, expr: &'a Expr) -> bool {
341+
fn visit_expr_with_let_maybe_allowed(&mut self, expr: &'a Expr, let_allowed: bool) -> bool {
340342
match &expr.node {
341343
// Assuming the context permits, `($expr)` does not impose additional constraints.
342-
ExprKind::Paren(_) => visit::walk_expr(self, expr),
344+
ExprKind::Paren(_) => {
345+
self.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
346+
}
343347
// Assuming the context permits,
344348
// l && r` allows decendants in `l` and `r` to be `let` expressions.
345-
ExprKind::Binary(op, ..) if op.node == BinOpKind::And => visit::walk_expr(self, expr),
349+
ExprKind::Binary(op, ..) if op.node == BinOpKind::And => {
350+
self.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
351+
}
346352
// However, we do allow it in the condition of the `if` expression.
347353
// We do not allow `let` in `then` and `opt_else` directly.
348-
ExprKind::If(ref cond, ref then, ref opt_else) => {
349-
self.with_let_allowed(false, |this| {
350-
this.visit_block(then);
351-
walk_list!(this, visit_expr, opt_else);
352-
});
353-
self.with_let_allowed(true, |this| this.visit_expr(cond));
354+
ExprKind::If(cond, then, opt_else) => {
355+
self.visit_block(then);
356+
walk_list!(self, visit_expr, opt_else);
357+
self.with_let_allowed(true, |this, _| this.visit_expr(cond));
354358
}
355359
// The same logic applies to `While`.
356-
ExprKind::While(ref cond, ref then, ref opt_label) => {
360+
ExprKind::While(cond, then, opt_label) => {
357361
walk_list!(self, visit_label, opt_label);
358-
self.with_let_allowed(false, |this| this.visit_block(then));
359-
self.with_let_allowed(true, |this| this.visit_expr(cond));
362+
self.visit_block(then);
363+
self.with_let_allowed(true, |this, _| this.visit_expr(cond));
360364
}
361365
// Don't walk into `expr` and defer further checks to the caller.
362366
_ => return false,
@@ -365,6 +369,15 @@ impl<'a> AstValidator<'a> {
365369
true
366370
}
367371

372+
/// Emits an error banning the `let` expression provided.
373+
fn ban_let_expr(&self, expr: &'a Expr) {
374+
self.err_handler()
375+
.struct_span_err(expr.span, "`let` expressions are not supported here")
376+
.note("only supported directly in conditions of `if`- and `while`-expressions")
377+
.note("as well as when nested within `&&` and parenthesis in those conditions")
378+
.emit();
379+
}
380+
368381
fn check_fn_decl(&self, fn_decl: &FnDecl) {
369382
fn_decl
370383
.inputs
@@ -491,28 +504,26 @@ fn validate_generics_order<'a>(
491504

492505
impl<'a> Visitor<'a> for AstValidator<'a> {
493506
fn visit_expr(&mut self, expr: &'a Expr) {
494-
match expr.node {
495-
ExprKind::Let(_, _) if !self.is_let_allowed => {
496-
self.err_handler()
497-
.struct_span_err(expr.span, "`let` expressions are not supported here")
498-
.note("only supported directly in conditions of `if`- and `while`-expressions")
499-
.note("as well as when nested within `&&` and parenthesis in those conditions")
500-
.emit();
501-
}
502-
_ if self.visit_expr_with_let_maybe_allowed(&expr) => {
503-
// Prevent `walk_expr` to happen since we've already done that.
504-
return;
505-
}
506-
ExprKind::Closure(_, _, _, ref fn_decl, _, _) => {
507-
self.check_fn_decl(fn_decl);
508-
}
509-
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
510-
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
507+
self.with_let_allowed(false, |this, let_allowed| {
508+
match &expr.node {
509+
ExprKind::Let(_, _) if !let_allowed => {
510+
this.ban_let_expr(expr);
511+
}
512+
_ if this.visit_expr_with_let_maybe_allowed(&expr, let_allowed) => {
513+
// Prevent `walk_expr` to happen since we've already done that.
514+
return;
515+
}
516+
ExprKind::Closure(_, _, _, fn_decl, _, _) => {
517+
this.check_fn_decl(fn_decl);
518+
}
519+
ExprKind::InlineAsm(..) if !this.session.target.target.options.allow_asm => {
520+
span_err!(this.session, expr.span, E0472, "asm! is unsupported on this target");
521+
}
522+
_ => {}
511523
}
512-
_ => {}
513-
}
514524

515-
self.with_let_allowed(false, |this| visit::walk_expr(this, expr));
525+
visit::walk_expr(this, expr);
526+
});
516527
}
517528

518529
fn visit_ty(&mut self, ty: &'a Ty) {

0 commit comments

Comments
 (0)