@@ -387,32 +387,58 @@ impl<'hir> LoweringContext<'_, 'hir> {
387387 then : & Block ,
388388 else_opt : Option < & Expr > ,
389389 ) -> hir:: ExprKind < ' hir > {
390- let lowered_cond = self . lower_expr ( cond) ;
391- let new_cond = self . manage_let_cond ( lowered_cond) ;
390+ let lowered_cond = self . lower_cond ( cond) ;
392391 let then_expr = self . lower_block_expr ( then) ;
393392 if let Some ( rslt) = else_opt {
394- hir:: ExprKind :: If ( new_cond, self . arena . alloc ( then_expr) , Some ( self . lower_expr ( rslt) ) )
393+ hir:: ExprKind :: If (
394+ lowered_cond,
395+ self . arena . alloc ( then_expr) ,
396+ Some ( self . lower_expr ( rslt) ) ,
397+ )
395398 } else {
396- hir:: ExprKind :: If ( new_cond , self . arena . alloc ( then_expr) , None )
399+ hir:: ExprKind :: If ( lowered_cond , self . arena . alloc ( then_expr) , None )
397400 }
398401 }
399402
400- // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
401- // in a temporary block .
402- fn manage_let_cond ( & mut self , cond : & ' hir hir :: Expr < ' hir > ) -> & ' hir hir:: Expr < ' hir > {
403- fn has_let_expr < ' hir > ( expr : & ' hir hir :: Expr < ' hir > ) -> bool {
404- match expr. kind {
405- hir :: ExprKind :: Binary ( _, lhs, rhs) => has_let_expr ( lhs) || has_let_expr ( rhs) ,
406- hir :: ExprKind :: Let ( ..) => true ,
403+ // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope
404+ // so that temporaries created in the condition don't live beyond it .
405+ fn lower_cond ( & mut self , cond : & Expr ) -> & ' hir hir:: Expr < ' hir > {
406+ fn has_let_expr ( expr : & Expr ) -> bool {
407+ match & expr. kind {
408+ ExprKind :: Binary ( _, lhs, rhs) => has_let_expr ( lhs) || has_let_expr ( rhs) ,
409+ ExprKind :: Let ( ..) => true ,
407410 _ => false ,
408411 }
409412 }
410- if has_let_expr ( cond) {
411- cond
412- } else {
413- let reason = DesugaringKind :: CondTemporary ;
414- let span_block = self . mark_span_with_reason ( reason, cond. span , None ) ;
415- self . expr_drop_temps ( span_block, cond, AttrVec :: new ( ) )
413+
414+ // We have to take special care for `let` exprs in the condition, e.g. in
415+ // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
416+ // condition in this case.
417+ //
418+ // In order to mantain the drop behavior for the non `let` parts of the condition,
419+ // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
420+ // gets transformed into `if { let _t = foo; _t } && let pat = val`
421+ match & cond. kind {
422+ ExprKind :: Binary ( op @ Spanned { node : ast:: BinOpKind :: And , .. } , lhs, rhs)
423+ if has_let_expr ( cond) =>
424+ {
425+ let op = self . lower_binop ( * op) ;
426+ let lhs = self . lower_cond ( lhs) ;
427+ let rhs = self . lower_cond ( rhs) ;
428+
429+ self . arena . alloc ( self . expr (
430+ cond. span ,
431+ hir:: ExprKind :: Binary ( op, lhs, rhs) ,
432+ AttrVec :: new ( ) ,
433+ ) )
434+ }
435+ ExprKind :: Let ( ..) => self . lower_expr ( cond) ,
436+ _ => {
437+ let cond = self . lower_expr ( cond) ;
438+ let reason = DesugaringKind :: CondTemporary ;
439+ let span_block = self . mark_span_with_reason ( reason, cond. span , None ) ;
440+ self . expr_drop_temps ( span_block, cond, AttrVec :: new ( ) )
441+ }
416442 }
417443 }
418444
@@ -439,14 +465,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
439465 body : & Block ,
440466 opt_label : Option < Label > ,
441467 ) -> hir:: ExprKind < ' hir > {
442- let lowered_cond = self . with_loop_condition_scope ( |t| t. lower_expr ( cond) ) ;
443- let new_cond = self . manage_let_cond ( lowered_cond) ;
468+ let lowered_cond = self . with_loop_condition_scope ( |t| t. lower_cond ( cond) ) ;
444469 let then = self . lower_block_expr ( body) ;
445470 let expr_break = self . expr_break ( span, AttrVec :: new ( ) ) ;
446471 let stmt_break = self . stmt_expr ( span, expr_break) ;
447472 let else_blk = self . block_all ( span, arena_vec ! [ self ; stmt_break] , None ) ;
448473 let else_expr = self . arena . alloc ( self . expr_block ( else_blk, AttrVec :: new ( ) ) ) ;
449- let if_kind = hir:: ExprKind :: If ( new_cond , self . arena . alloc ( then) , Some ( else_expr) ) ;
474+ let if_kind = hir:: ExprKind :: If ( lowered_cond , self . arena . alloc ( then) , Some ( else_expr) ) ;
450475 let if_expr = self . expr ( span, if_kind, AttrVec :: new ( ) ) ;
451476 let block = self . block_expr ( self . arena . alloc ( if_expr) ) ;
452477 let span = self . lower_span ( span. with_hi ( cond. span . hi ( ) ) ) ;
0 commit comments