@@ -103,8 +103,10 @@ impl<'a> AstValidator<'a> {
103
103
with ( self , outer, |this| & mut this. outer_impl_trait , f)
104
104
}
105
105
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;
108
110
}
109
111
110
112
fn visit_assoc_type_binding_from_generic_args ( & mut self , type_binding : & ' a TypeBinding ) {
@@ -338,34 +340,45 @@ impl<'a> AstValidator<'a> {
338
340
/// Visits the `expr` and adjusts whether `let $pat = $expr` is allowed in decendants.
339
341
/// Returns whether we walked into `expr` or not.
340
342
/// 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 {
342
344
match & expr. node {
343
345
// 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
+ }
345
349
// Assuming the context permits,
346
350
// 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
+ }
348
354
// However, we do allow it in the condition of the `if` expression.
349
355
// 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) ) ;
356
360
}
357
361
// The same logic applies to `While`.
358
- ExprKind :: While ( ref cond, ref then, ref opt_label) => {
362
+ ExprKind :: While ( cond, then, opt_label) => {
359
363
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) ) ;
362
366
}
363
367
// Don't walk into `expr` and defer further checks to the caller.
364
368
_ => return false ,
365
369
}
366
370
367
371
true
368
372
}
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
+ }
369
382
}
370
383
371
384
enum GenericPosition {
@@ -470,28 +483,26 @@ fn validate_generics_order<'a>(
470
483
471
484
impl < ' a > Visitor < ' a > for AstValidator < ' a > {
472
485
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
+ _ => { }
490
502
}
491
- _ => { }
492
- }
493
503
494
- self . with_let_allowed ( false , |this| visit:: walk_expr ( this, expr) ) ;
504
+ visit:: walk_expr ( this, expr) ;
505
+ } ) ;
495
506
}
496
507
497
508
fn visit_ty ( & mut self , ty : & ' a Ty ) {
0 commit comments