@@ -387,32 +387,58 @@ impl<'hir> LoweringContext<'_, 'hir> {
387
387
then : & Block ,
388
388
else_opt : Option < & Expr > ,
389
389
) -> 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) ;
392
391
let then_expr = self . lower_block_expr ( then) ;
393
392
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
+ )
395
398
} 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 )
397
400
}
398
401
}
399
402
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 ,
407
410
_ => false ,
408
411
}
409
412
}
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
+ }
416
442
}
417
443
}
418
444
@@ -439,14 +465,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
439
465
body : & Block ,
440
466
opt_label : Option < Label > ,
441
467
) -> 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) ) ;
444
469
let then = self . lower_block_expr ( body) ;
445
470
let expr_break = self . expr_break ( span, AttrVec :: new ( ) ) ;
446
471
let stmt_break = self . stmt_expr ( span, expr_break) ;
447
472
let else_blk = self . block_all ( span, arena_vec ! [ self ; stmt_break] , None ) ;
448
473
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) ) ;
450
475
let if_expr = self . expr ( span, if_kind, AttrVec :: new ( ) ) ;
451
476
let block = self . block_expr ( self . arena . alloc ( if_expr) ) ;
452
477
let span = self . lower_span ( span. with_hi ( cond. span . hi ( ) ) ) ;
0 commit comments