@@ -114,8 +114,10 @@ impl<'a> AstValidator<'a> {
114
114
with ( self , outer, |this| & mut this. outer_impl_trait , f)
115
115
}
116
116
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;
119
121
}
120
122
121
123
fn visit_assoc_ty_constraint_from_generic_args ( & mut self , constraint : & ' a AssocTyConstraint ) {
@@ -336,27 +338,29 @@ impl<'a> AstValidator<'a> {
336
338
/// Visits the `expr` and adjusts whether `let $pat = $expr` is allowed in decendants.
337
339
/// Returns whether we walked into `expr` or not.
338
340
/// 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 {
340
342
match & expr. node {
341
343
// 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
+ }
343
347
// Assuming the context permits,
344
348
// 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
+ }
346
352
// However, we do allow it in the condition of the `if` expression.
347
353
// 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) ) ;
354
358
}
355
359
// The same logic applies to `While`.
356
- ExprKind :: While ( ref cond, ref then, ref opt_label) => {
360
+ ExprKind :: While ( cond, then, opt_label) => {
357
361
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) ) ;
360
364
}
361
365
// Don't walk into `expr` and defer further checks to the caller.
362
366
_ => return false ,
@@ -365,6 +369,15 @@ impl<'a> AstValidator<'a> {
365
369
true
366
370
}
367
371
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
+
368
381
fn check_fn_decl ( & self , fn_decl : & FnDecl ) {
369
382
fn_decl
370
383
. inputs
@@ -491,28 +504,26 @@ fn validate_generics_order<'a>(
491
504
492
505
impl < ' a > Visitor < ' a > for AstValidator < ' a > {
493
506
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
+ _ => { }
511
523
}
512
- _ => { }
513
- }
514
524
515
- self . with_let_allowed ( false , |this| visit:: walk_expr ( this, expr) ) ;
525
+ visit:: walk_expr ( this, expr) ;
526
+ } ) ;
516
527
}
517
528
518
529
fn visit_ty ( & mut self , ty : & ' a Ty ) {
0 commit comments