Skip to content

Commit f607ff1

Browse files
committed
let_chains: Change AST validation strategy slightly.
1 parent 2178db4 commit f607ff1

File tree

1 file changed

+45
-34
lines changed

1 file changed

+45
-34
lines changed

Diff for: src/librustc_passes/ast_validation.rs

+45-34
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,10 @@ impl<'a> AstValidator<'a> {
103103
with(self, outer, |this| &mut this.outer_impl_trait, f)
104104
}
105105

106-
fn with_let_allowed(&mut self, v: bool, f: impl FnOnce(&mut Self)) {
107-
with(self, v, |this| &mut this.is_let_allowed, f)
106+
fn with_let_allowed(&mut self, v: bool, f: impl FnOnce(&mut Self, bool)) {
107+
let old = mem::replace(&mut self.is_let_allowed, v);
108+
f(self, old);
109+
self.is_let_allowed = old;
108110
}
109111

110112
fn visit_assoc_type_binding_from_generic_args(&mut self, type_binding: &'a TypeBinding) {
@@ -338,34 +340,45 @@ impl<'a> AstValidator<'a> {
338340
/// Visits the `expr` and adjusts whether `let $pat = $expr` is allowed in decendants.
339341
/// Returns whether we walked into `expr` or not.
340342
/// If we did, walking should not happen again.
341-
fn visit_expr_with_let_maybe_allowed(&mut self, expr: &'a Expr) -> bool {
343+
fn visit_expr_with_let_maybe_allowed(&mut self, expr: &'a Expr, let_allowed: bool) -> bool {
342344
match &expr.node {
343345
// Assuming the context permits, `($expr)` does not impose additional constraints.
344-
ExprKind::Paren(_) => visit::walk_expr(self, expr),
346+
ExprKind::Paren(_) => {
347+
self.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
348+
}
345349
// Assuming the context permits,
346350
// l && r` allows decendants in `l` and `r` to be `let` expressions.
347-
ExprKind::Binary(op, ..) if op.node == BinOpKind::And => visit::walk_expr(self, expr),
351+
ExprKind::Binary(op, ..) if op.node == BinOpKind::And => {
352+
self.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
353+
}
348354
// However, we do allow it in the condition of the `if` expression.
349355
// We do not allow `let` in `then` and `opt_else` directly.
350-
ExprKind::If(ref cond, ref then, ref opt_else) => {
351-
self.with_let_allowed(false, |this| {
352-
this.visit_block(then);
353-
walk_list!(this, visit_expr, opt_else);
354-
});
355-
self.with_let_allowed(true, |this| this.visit_expr(cond));
356+
ExprKind::If(cond, then, opt_else) => {
357+
self.visit_block(then);
358+
walk_list!(self, visit_expr, opt_else);
359+
self.with_let_allowed(true, |this, _| this.visit_expr(cond));
356360
}
357361
// The same logic applies to `While`.
358-
ExprKind::While(ref cond, ref then, ref opt_label) => {
362+
ExprKind::While(cond, then, opt_label) => {
359363
walk_list!(self, visit_label, opt_label);
360-
self.with_let_allowed(false, |this| this.visit_block(then));
361-
self.with_let_allowed(true, |this| this.visit_expr(cond));
364+
self.visit_block(then);
365+
self.with_let_allowed(true, |this, _| this.visit_expr(cond));
362366
}
363367
// Don't walk into `expr` and defer further checks to the caller.
364368
_ => return false,
365369
}
366370

367371
true
368372
}
373+
374+
/// Emits an error banning the `let` expression provided.
375+
fn ban_let_expr(&self, expr: &'a Expr) {
376+
self.err_handler()
377+
.struct_span_err(expr.span, "`let` expressions are not supported here")
378+
.note("only supported directly in conditions of `if`- and `while`-expressions")
379+
.note("as well as when nested within `&&` and parenthesis in those conditions")
380+
.emit();
381+
}
369382
}
370383

371384
enum GenericPosition {
@@ -470,28 +483,26 @@ fn validate_generics_order<'a>(
470483

471484
impl<'a> Visitor<'a> for AstValidator<'a> {
472485
fn visit_expr(&mut self, expr: &'a Expr) {
473-
match expr.node {
474-
ExprKind::Let(_, _) if !self.is_let_allowed => {
475-
self.err_handler()
476-
.struct_span_err(expr.span, "`let` expressions are not supported here")
477-
.note("only supported directly in conditions of `if`- and `while`-expressions")
478-
.note("as well as when nested within `&&` and parenthesis in those conditions")
479-
.emit();
480-
}
481-
_ if self.visit_expr_with_let_maybe_allowed(&expr) => {
482-
// Prevent `walk_expr` to happen since we've already done that.
483-
return;
484-
}
485-
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
486-
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
487-
}
488-
ExprKind::ObsoleteInPlace(ref place, ref val) => {
489-
self.obsolete_in_place(expr, place, val);
486+
self.with_let_allowed(false, |this, let_allowed| {
487+
match &expr.node {
488+
ExprKind::Let(_, _) if !let_allowed => {
489+
this.ban_let_expr(expr);
490+
}
491+
_ if this.visit_expr_with_let_maybe_allowed(&expr, let_allowed) => {
492+
// Prevent `walk_expr` to happen since we've already done that.
493+
return;
494+
}
495+
ExprKind::InlineAsm(..) if !this.session.target.target.options.allow_asm => {
496+
span_err!(this.session, expr.span, E0472, "asm! is unsupported on this target");
497+
}
498+
ExprKind::ObsoleteInPlace(place, val) => {
499+
this.obsolete_in_place(expr, place, val);
500+
}
501+
_ => {}
490502
}
491-
_ => {}
492-
}
493503

494-
self.with_let_allowed(false, |this| visit::walk_expr(this, expr));
504+
visit::walk_expr(this, expr);
505+
});
495506
}
496507

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

0 commit comments

Comments
 (0)