@@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
388388 else_opt : Option < & Expr > ,
389389 ) -> hir:: ExprKind < ' hir > {
390390 let lowered_cond = self . lower_expr ( cond) ;
391- let new_cond = self . manage_let_cond ( lowered_cond) ;
391+ let new_cond = self . wrap_cond_in_drop_scope ( lowered_cond) ;
392392 let then_expr = self . lower_block_expr ( then) ;
393393 if let Some ( rslt) = else_opt {
394394 hir:: ExprKind :: If ( new_cond, self . arena . alloc ( then_expr) , Some ( self . lower_expr ( rslt) ) )
@@ -397,22 +397,45 @@ impl<'hir> LoweringContext<'_, 'hir> {
397397 }
398398 }
399399
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 > {
400+ // Wraps a condition (i.e. `cond` in `if cond` or `while cond`) in a terminating scope
401+ // so that temporaries created in the condition don't live beyond it .
402+ fn wrap_cond_in_drop_scope ( & mut self , cond : & ' hir hir:: Expr < ' hir > ) -> & ' hir hir:: Expr < ' hir > {
403403 fn has_let_expr < ' hir > ( expr : & ' hir hir:: Expr < ' hir > ) -> bool {
404404 match expr. kind {
405405 hir:: ExprKind :: Binary ( _, lhs, rhs) => has_let_expr ( lhs) || has_let_expr ( rhs) ,
406406 hir:: ExprKind :: Let ( ..) => true ,
407407 _ => false ,
408408 }
409409 }
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 ( ) )
410+
411+ // We have to take special care for `let` exprs in the condition, e.g. in
412+ // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
413+ // condition in this case.
414+ //
415+ // In order to mantain the drop behavior for the non `let` parts of the condition,
416+ // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
417+ // gets transformed into `if { let _t = foo; _t } && let pat = val`
418+ match cond. kind {
419+ hir:: ExprKind :: Binary (
420+ op @ Spanned { node : hir:: BinOpKind :: And | hir:: BinOpKind :: Or , .. } ,
421+ lhs,
422+ rhs,
423+ ) if has_let_expr ( cond) => {
424+ let lhs = self . wrap_cond_in_drop_scope ( lhs) ;
425+ let rhs = self . wrap_cond_in_drop_scope ( rhs) ;
426+
427+ self . arena . alloc ( self . expr (
428+ cond. span ,
429+ hir:: ExprKind :: Binary ( op, lhs, rhs) ,
430+ AttrVec :: new ( ) ,
431+ ) )
432+ }
433+ hir:: ExprKind :: Let ( _) => cond,
434+ _ => {
435+ let reason = DesugaringKind :: CondTemporary ;
436+ let span_block = self . mark_span_with_reason ( reason, cond. span , None ) ;
437+ self . expr_drop_temps ( span_block, cond, AttrVec :: new ( ) )
438+ }
416439 }
417440 }
418441
@@ -440,7 +463,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
440463 opt_label : Option < Label > ,
441464 ) -> hir:: ExprKind < ' hir > {
442465 let lowered_cond = self . with_loop_condition_scope ( |t| t. lower_expr ( cond) ) ;
443- let new_cond = self . manage_let_cond ( lowered_cond) ;
466+ let new_cond = self . wrap_cond_in_drop_scope ( lowered_cond) ;
444467 let then = self . lower_block_expr ( body) ;
445468 let expr_break = self . expr_break ( span, AttrVec :: new ( ) ) ;
446469 let stmt_break = self . stmt_expr ( span, expr_break) ;
0 commit comments