about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2021-02-25 22:37:22 +0000
committerCaio <c410.f3r@gmail.com>2021-08-15 16:05:25 -0300
commit2d9f2eae84dc3988c5463fdd1b124a9b695447d7 (patch)
tree373c546d14e21ad7e4315d367c145f7ae00739b2
parentc0490a2dbbb94f8244fb6a15ca5d33dc3fcd268a (diff)
downloadrust-2d9f2eae84dc3988c5463fdd1b124a9b695447d7.tar.gz
rust-2d9f2eae84dc3988c5463fdd1b124a9b695447d7.zip
Use correct drop scopes for if expressions
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs17
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs41
-rw-r--r--compiler/rustc_passes/src/region.rs24
3 files changed, 75 insertions, 7 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index bacf5662bc0..3bf7c7c37a4 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -443,9 +443,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
         else_opt: Option<&Expr>,
     ) -> hir::ExprKind<'hir> {
         let cond = self.lower_expr(cond);
-        let then = self.arena.alloc(self.lower_block_expr(then));
-        let els = else_opt.map(|els| self.lower_expr(els));
-        hir::ExprKind::If(cond, then, els)
+        let wrapped_cond = match cond.kind {
+            hir::ExprKind::Let(..) => cond,
+            _ => self.expr_drop_temps(cond.span, cond, AttrVec::new()),
+        };
+        let then_expr = self.lower_block_expr(then);
+        if let Some(rslt) = else_opt {
+            hir::ExprKind::If(
+                wrapped_cond,
+                self.arena.alloc(then_expr),
+                Some(self.lower_expr(rslt)),
+            )
+        } else {
+            hir::ExprKind::If(wrapped_cond, self.arena.alloc(then_expr), None)
+        }
     }
 
     fn lower_expr_if_let(
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 8164529dd1f..9ca4425a1b5 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -35,6 +35,47 @@ use std::convert::TryFrom;
 use std::mem;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
+    pub(crate) fn then_else_blocks(
+        &mut self,
+        mut block: BasicBlock,
+        expr: ExprRef<'tcx>,
+        source_info: SourceInfo,
+    ) -> (BasicBlock, BasicBlock) {
+        let this = self;
+        let expr = this.hir.mirror(expr);
+        let expr_span = expr.span;
+
+        match expr.kind {
+            ExprKind::Scope { region_scope, lint_level, value } => {
+                let region_scope = (region_scope, source_info);
+                let then_block;
+                let else_block = unpack!(
+                    then_block = this.in_scope(region_scope, lint_level, |this| {
+                        let (then_block, else_block) =
+                            this.then_else_blocks(block, value, source_info);
+                        then_block.and(else_block)
+                    })
+                );
+                (then_block, else_block)
+            }
+            ExprKind::Let { expr, pat } => {
+                // TODO: Use correct span.
+                this.lower_let(block, &expr, &pat, expr_span)
+            }
+            _ => {
+                let local_scope = Some(this.local_scope());
+                let place =
+                    unpack!(block = this.as_temp(block, local_scope, expr, Mutability::Mut));
+                let operand = Operand::Move(Place::from(place));
+                let then_block = this.cfg.start_new_block();
+                let else_block = this.cfg.start_new_block();
+                let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
+                this.cfg.terminate(block, source_info, term);
+                (then_block, else_block)
+            }
+        }
+    }
+
     /// Generates MIR for a `match` expression.
     ///
     /// The MIR that we generate for a match looks like this.
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index c133f1a0417..7403e51c734 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -233,14 +233,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
                 terminating(r.hir_id.local_id);
             }
 
-            hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => {
-                terminating(expr.hir_id.local_id);
+            hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
                 terminating(then.hir_id.local_id);
                 terminating(otherwise.hir_id.local_id);
             }
 
-            hir::ExprKind::If(ref expr, ref then, None) => {
-                terminating(expr.hir_id.local_id);
+            hir::ExprKind::If(_, ref then, None) => {
                 terminating(then.hir_id.local_id);
             }
 
@@ -392,6 +390,24 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             }
         }
 
+        hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
+            // FIXME(matthewjasper): ideally the scope we use here would only
+            // contain the condition and then expression. This works, but
+            // can result in some extra drop flags.
+            visitor.cx.var_parent = visitor.cx.parent;
+            visitor.visit_expr(cond);
+            visitor.cx.var_parent = prev_cx.var_parent;
+            visitor.visit_expr(then);
+            visitor.visit_expr(otherwise);
+        }
+
+        hir::ExprKind::If(ref cond, ref then, None) => {
+            visitor.cx.var_parent = visitor.cx.parent;
+            visitor.visit_expr(cond);
+            visitor.cx.var_parent = prev_cx.var_parent;
+            visitor.visit_expr(then);
+        }
+
         _ => intravisit::walk_expr(visitor, expr),
     }