@@ -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
371384enum GenericPosition {
@@ -470,28 +483,26 @@ fn validate_generics_order<'a>(
470483
471484impl < ' 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