about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/expr/as_lvalue.rs8
-rw-r--r--src/librustc_mir/build/expr/as_operand.rs32
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs53
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs21
-rw-r--r--src/librustc_mir/build/expr/into.rs16
-rw-r--r--src/librustc_mir/build/expr/stmt.rs8
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/build/scope.rs10
-rw-r--r--src/test/mir-opt/basic_assignment.rs85
-rw-r--r--src/test/mir-opt/issue-38669.rs52
-rw-r--r--src/test/mir-opt/storage_ranges.rs5
-rw-r--r--src/test/run-pass/mir_drop_order.rs21
12 files changed, 257 insertions, 56 deletions
diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs
index 5abfe084f22..8886a310429 100644
--- a/src/librustc_mir/build/expr/as_lvalue.rs
+++ b/src/librustc_mir/build/expr/as_lvalue.rs
@@ -56,8 +56,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
 
                 let slice = unpack!(block = this.as_lvalue(block, lhs));
-
-                let idx = unpack!(block = this.as_operand(block, index));
+                // extent=None so lvalue indexes live forever. They are scalars so they
+                // do not need storage annotations, and they are often copied between
+                // places.
+                let idx = unpack!(block = this.as_operand(block, None, index));
 
                 // bounds check:
                 let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
@@ -121,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Some(Category::Lvalue) => false,
                     _ => true,
                 });
-                this.as_temp(block, expr)
+                this.as_temp(block, expr.temp_lifetime, expr)
             }
         }
     }
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index 09cdcc74ef6..8d79e755685 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -13,29 +13,52 @@
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::Category;
 use hair::*;
+use rustc::middle::region::CodeExtent;
 use rustc::mir::*;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
+    /// Returns an operand suitable for use until the end of the current
+    /// scope expression.
+    ///
+    /// The operand returned from this function will *not be valid* after
+    /// an ExprKind::Scope is passed, so please do *not* return it from
+    /// functions to avoid bad miscompiles.
+    pub fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M)
+                             -> BlockAnd<Operand<'tcx>>
+        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    {
+        let topmost_scope = self.topmost_scope(); // FIXME(#6393)
+        self.as_operand(block, Some(topmost_scope), expr)
+    }
+
     /// Compile `expr` into a value that can be used as an operand.
     /// If `expr` is an lvalue like `x`, this will introduce a
     /// temporary `tmp = x`, so that we capture the value of `x` at
     /// this time.
-    pub fn as_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
+    ///
+    /// The operand is known to be live until the end of `scope`.
+    pub fn as_operand<M>(&mut self,
+                         block: BasicBlock,
+                         scope: Option<CodeExtent>,
+                         expr: M) -> BlockAnd<Operand<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_operand(block, expr)
+        self.expr_as_operand(block, scope, expr)
     }
 
     fn expr_as_operand(&mut self,
                        mut block: BasicBlock,
+                       scope: Option<CodeExtent>,
                        expr: Expr<'tcx>)
                        -> BlockAnd<Operand<'tcx>> {
         debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
 
         if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this| this.as_operand(block, value));
+            return this.in_scope(extent, block, |this| {
+                this.as_operand(block, scope, value)
+            });
         }
 
         let category = Category::of(&expr.kind).unwrap();
@@ -47,7 +70,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
             Category::Lvalue |
             Category::Rvalue(..) => {
-                let operand = unpack!(block = this.as_temp(block, expr));
+                let operand =
+                    unpack!(block = this.as_temp(block, scope, expr));
                 block.and(Operand::Consume(operand))
             }
         }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 7f5d9c36ece..961713bcfe6 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -21,22 +21,34 @@ use build::expr::category::{Category, RvalueFunc};
 use hair::*;
 use rustc_const_math::{ConstInt, ConstIsize};
 use rustc::middle::const_val::ConstVal;
+use rustc::middle::region::CodeExtent;
 use rustc::ty;
 use rustc::mir::*;
 use syntax::ast;
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
+    /// See comment on `as_local_operand`
+    pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M)
+                             -> BlockAnd<Rvalue<'tcx>>
+        where M: Mirror<'tcx, Output = Expr<'tcx>>
+    {
+        let topmost_scope = self.topmost_scope(); // FIXME(#6393)
+        self.as_rvalue(block, Some(topmost_scope), expr)
+    }
+
     /// Compile `expr`, yielding an rvalue.
-    pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
+    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
+                        -> BlockAnd<Rvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_rvalue(block, expr)
+        self.expr_as_rvalue(block, scope, expr)
     }
 
     fn expr_as_rvalue(&mut self,
                       mut block: BasicBlock,
+                      scope: Option<CodeExtent>,
                       expr: Expr<'tcx>)
                       -> BlockAnd<Rvalue<'tcx>> {
         debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
@@ -47,10 +59,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         match expr.kind {
             ExprKind::Scope { extent, value } => {
-                this.in_scope(extent, block, |this| this.as_rvalue(block, value))
+                this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value))
             }
             ExprKind::Repeat { value, count } => {
-                let value_operand = unpack!(block = this.as_operand(block, value));
+                let value_operand = unpack!(block = this.as_operand(block, scope, value));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Borrow { region, borrow_kind, arg } => {
@@ -58,13 +70,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block.and(Rvalue::Ref(region, borrow_kind, arg_lvalue))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, lhs));
-                let rhs = unpack!(block = this.as_operand(block, rhs));
+                let lhs = unpack!(block = this.as_operand(block, scope, lhs));
+                let rhs = unpack!(block = this.as_operand(block, scope, rhs));
                 this.build_binary_op(block, op, expr_span, expr.ty,
                                      lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, arg));
+                let arg = unpack!(block = this.as_operand(block, scope, arg));
                 // Check for -MIN on signed integers
                 if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.hir.bool_ty();
@@ -97,27 +109,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Cast { source } => {
                 let source = this.hir.mirror(source);
 
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Use { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Use(source))
             }
             ExprKind::ReifyFnPointer { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty))
             }
             ExprKind::UnsafeFnPointer { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
             }
             ExprKind::ClosureFnPointer { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
             }
             ExprKind::Unsize { source } => {
-                let source = unpack!(block = this.as_operand(block, source));
+                let source = unpack!(block = this.as_operand(block, scope, source));
                 block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
             }
             ExprKind::Array { fields } => {
@@ -150,7 +162,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // first process the set of fields
                 let fields: Vec<_> =
                     fields.into_iter()
-                          .map(|f| unpack!(block = this.as_operand(block, f)))
+                          .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                           .collect();
 
                 block.and(Rvalue::Aggregate(AggregateKind::Array, fields))
@@ -159,7 +171,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // first process the set of fields
                 let fields: Vec<_> =
                     fields.into_iter()
-                          .map(|f| unpack!(block = this.as_operand(block, f)))
+                          .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                           .collect();
 
                 block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields))
@@ -167,7 +179,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above
                 let upvars =
                     upvars.into_iter()
-                          .map(|upvar| unpack!(block = this.as_operand(block, upvar)))
+                          .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
                           .collect();
                 block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
             }
@@ -179,10 +191,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 // first process the set of fields that were provided
                 // (evaluating them in order given by user)
-                let fields_map: FxHashMap<_, _> =
-                    fields.into_iter()
-                          .map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
-                          .collect();
+                let fields_map: FxHashMap<_, _> = fields.into_iter()
+                    .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
+                    .collect();
 
                 let field_names = this.hir.all_fields(adt_def, variant_index);
 
@@ -235,7 +246,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
                     _ => true,
                 });
-                let operand = unpack!(block = this.as_operand(block, expr));
+                let operand = unpack!(block = this.as_operand(block, scope, expr));
                 block.and(Rvalue::Use(operand))
             }
         }
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 0ae4bcc4205..69b95702009 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -13,29 +13,38 @@
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::expr::category::Category;
 use hair::*;
+use rustc::middle::region::CodeExtent;
 use rustc::mir::*;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr` into a fresh temporary. This is used when building
     /// up rvalues so as to freeze the value that will be consumed.
-    pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>>
+    pub fn as_temp<M>(&mut self,
+                      block: BasicBlock,
+                      temp_lifetime: Option<CodeExtent>,
+                      expr: M)
+                      -> BlockAnd<Lvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
         let expr = self.hir.mirror(expr);
-        self.expr_as_temp(block, expr)
+        self.expr_as_temp(block, temp_lifetime, expr)
     }
 
-    fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<Lvalue<'tcx>> {
+    fn expr_as_temp(&mut self,
+                    mut block: BasicBlock,
+                    temp_lifetime: Option<CodeExtent>,
+                    expr: Expr<'tcx>)
+                    -> BlockAnd<Lvalue<'tcx>> {
         debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
         let this = self;
 
-        if let ExprKind::Scope { extent, value } = expr.kind {
-            return this.in_scope(extent, block, |this| this.as_temp(block, value));
+        if let ExprKind::Scope { .. } = expr.kind {
+            span_bug!(expr.span, "unexpected scope expression in as_temp: {:?}",
+                      expr);
         }
 
         let expr_ty = expr.ty.clone();
         let temp = this.temp(expr_ty.clone());
-        let temp_lifetime = expr.temp_lifetime;
         let expr_span = expr.span;
         let source_info = this.source_info(expr_span);
 
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index ae51951b519..dab85106873 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     _ => false,
                 };
 
-                unpack!(block = this.as_rvalue(block, source));
+                unpack!(block = this.as_local_rvalue(block, source));
 
                 // This is an optimization. If the expression was a call then we already have an
                 // unreachable block. Don't bother to terminate it and create a new one.
@@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
             ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
-                let operand = unpack!(block = this.as_operand(block, cond_expr));
+                let operand = unpack!(block = this.as_local_operand(block, cond_expr));
 
                 let mut then_block = this.cfg.start_new_block();
                 let mut else_block = this.cfg.start_new_block();
@@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     (this.cfg.start_new_block(), this.cfg.start_new_block(),
                      this.cfg.start_new_block(), this.cfg.start_new_block());
 
-                let lhs = unpack!(block = this.as_operand(block, lhs));
+                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                 let blocks = match op {
                     LogicalOp::And => (else_block, false_block),
                     LogicalOp::Or => (true_block, else_block),
@@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                 this.cfg.terminate(block, source_info, term);
 
-                let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
+                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                 let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                 this.cfg.terminate(else_block, source_info, term);
 
@@ -173,7 +173,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         if let Some(cond_expr) = opt_cond_expr {
                             let loop_block_end;
                             let cond = unpack!(
-                                loop_block_end = this.as_operand(loop_block, cond_expr));
+                                loop_block_end = this.as_local_operand(loop_block, cond_expr));
                             body_block = this.cfg.start_new_block();
                             let term = TerminatorKind::if_(this.hir.tcx(), cond,
                                                            body_block, exit_block);
@@ -206,10 +206,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     }
                     _ => false
                 };
-                let fun = unpack!(block = this.as_operand(block, fun));
+                let fun = unpack!(block = this.as_local_operand(block, fun));
                 let args: Vec<_> =
                     args.into_iter()
-                        .map(|arg| unpack!(block = this.as_operand(block, arg)))
+                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
                         .collect();
 
                 let success = this.cfg.start_new_block();
@@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     _ => true,
                 });
 
-                let rvalue = unpack!(block = this.as_rvalue(block, expr));
+                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
                 block.unit()
             }
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
index c577aab40db..be39dcbf6d0 100644
--- a/src/librustc_mir/build/expr/stmt.rs
+++ b/src/librustc_mir/build/expr/stmt.rs
@@ -38,14 +38,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // Generate better code for things that don't need to be
                 // dropped.
                 if this.hir.needs_drop(lhs.ty) {
-                    let rhs = unpack!(block = this.as_operand(block, rhs));
+                    let rhs = unpack!(block = this.as_local_operand(block, rhs));
                     let lhs = unpack!(block = this.as_lvalue(block, lhs));
                     unpack!(block = this.build_drop_and_replace(
                         block, lhs_span, lhs, rhs
                     ));
                     block.unit()
                 } else {
-                    let rhs = unpack!(block = this.as_rvalue(block, rhs));
+                    let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
                     let lhs = unpack!(block = this.as_lvalue(block, lhs));
                     this.cfg.push_assign(block, source_info, &lhs, rhs);
                     block.unit()
@@ -64,7 +64,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let lhs_ty = lhs.ty;
 
                 // As above, RTL.
-                let rhs = unpack!(block = this.as_operand(block, rhs));
+                let rhs = unpack!(block = this.as_local_operand(block, rhs));
                 let lhs = unpack!(block = this.as_lvalue(block, lhs));
 
                 // we don't have to drop prior contents or anything
@@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     unpack!(block = this.as_lvalue(block, output))
                 }).collect();
                 let inputs = inputs.into_iter().map(|input| {
-                    unpack!(block = this.as_operand(block, input))
+                    unpack!(block = this.as_local_operand(block, input))
                 }).collect();
                 this.cfg.push(block, Statement {
                     source_info: source_info,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index fd39f511e6d..705eb1f5660 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -661,7 +661,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // guard, this block is simply unreachable
             let guard = self.hir.mirror(guard);
             let source_info = self.source_info(guard.span);
-            let cond = unpack!(block = self.as_operand(block, guard));
+            let cond = unpack!(block = self.as_local_operand(block, guard));
             let otherwise = self.cfg.start_new_block();
             self.cfg.terminate(block, source_info,
                                TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 282361fc13e..3dab1717f6b 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -253,9 +253,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             f: F)
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
     {
-        let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
+        let extent = self.topmost_scope();
         let loop_scope = LoopScope {
-            extent: extent.clone(),
+            extent: extent,
             continue_block: loop_block,
             break_block: break_block,
             break_destination: break_destination,
@@ -416,6 +416,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         self.scopes[1].extent
     }
 
+    /// Returns the topmost active scope, which is known to be alive until
+    /// the next scope expression.
+    pub fn topmost_scope(&self) -> CodeExtent {
+        self.scopes.last().expect("topmost_scope: no scopes present").extent
+    }
+
     // Scheduling drops
     // ================
     /// Indicates that `lvalue` should be dropped on exit from
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
new file mode 100644
index 00000000000..9c924a23903
--- /dev/null
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -0,0 +1,85 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// this tests move up progration, which is not yet implemented
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that codegen of assignment expressions is sane. Assignments
+// tend to be absent in simple code, so subtle breakage in them can
+// leave a quite hard-to-find trail of destruction.
+
+fn main() {
+    let nodrop_x = false;
+    let nodrop_y;
+
+    nodrop_y = nodrop_x;
+
+    let drop_x : Option<Box<u32>> = None;
+    let drop_y;
+
+    drop_y = drop_x;
+}
+
+// END RUST SOURCE
+// START rustc.node4.SimplifyCfg.initial-after.mir
+//     bb0: {
+//         StorageLive(_1);
+//         _1 = const false;
+//         StorageLive(_2);
+//         StorageLive(_3);
+//         _3 = _1;
+//         _2 = _3;
+//         StorageDead(_3);
+//         StorageLive(_4);
+//         _4 = std::option::Option<std::boxed::Box<u32>>::None;
+//         StorageLive(_6);
+//         StorageLive(_7);
+//         _7 = _4;
+//         replace(_6 <- _7) -> [return: bb5, unwind: bb4];
+//     }
+//     bb1: {
+//         resume;
+//     }
+//     bb2: {
+//         drop(_4) -> bb1;
+//     }
+//     bb3: {
+//         drop(_6) -> bb2;
+//     }
+//     bb4: {
+//         drop(_7) -> bb3;
+//     }
+//     bb5: {
+//         drop(_7) -> [return: bb6, unwind: bb3];
+//     }
+//     bb6: {
+//         StorageDead(_7);
+//         _0 = ();
+//         drop(_6) -> [return: bb7, unwind: bb2];
+//     }
+//     bb7: {
+//         StorageDead(_6);
+//         drop(_4) -> bb8;
+//     }
+//     bb8: {
+//         StorageDead(_4);
+//         StorageDead(_2);
+//         StorageDead(_1);
+//         return;
+//     }
+// END rustc.node4.SimplifyCfg.initial-after.mir
diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs
new file mode 100644
index 00000000000..1d452907cf5
--- /dev/null
+++ b/src/test/mir-opt/issue-38669.rs
@@ -0,0 +1,52 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that we don't StorageDead booleans before they are used
+
+fn main() {
+    let mut should_break = false;
+    loop {
+        if should_break {
+            break;
+        }
+        should_break = true;
+    }
+}
+
+// END RUST SOURCE
+// START rustc.node4.SimplifyCfg.initial-after.mir
+//     bb0: {
+//         StorageLive(_1);
+//         _1 = const false;
+//         goto -> bb1;
+//     }
+//
+//     bb1: {
+//         StorageLive(_4);
+//         _4 = _1;
+//         switchInt(_4) -> [0u8: bb3, otherwise: bb2];
+//     }
+//
+//     bb2: {
+//         StorageLive(_6);
+//         _0 = ();
+//         StorageDead(_4);
+//         StorageDead(_1);
+//         return;
+//     }
+//
+//     bb3: {
+//         _3 = ();
+//         StorageDead(_4);
+//         _1 = const true;
+//         _2 = ();
+//         goto -> bb1;
+//     }
+// END rustc.node4.SimplifyCfg.initial-after.mir
diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs
index c63db741e5a..3fbd1a36f2f 100644
--- a/src/test/mir-opt/storage_ranges.rs
+++ b/src/test/mir-opt/storage_ranges.rs
@@ -28,8 +28,8 @@ fn main() {
 //         StorageLive(_5);
 //         _5 = _1;
 //         _4 = std::option::Option<i32>::Some(_5,);
-//         _3 = &_4;
 //         StorageDead(_5);
+//         _3 = &_4;
 //         _2 = ();
 //         StorageDead(_3);
 //         StorageDead(_4);
@@ -38,6 +38,5 @@ fn main() {
 //         _0 = ();
 //         StorageDead(_6);
 //         StorageDead(_1);
-//         return;
-//     }
+//      }
 // END rustc.node4.TypeckMir.before.mir
diff --git a/src/test/run-pass/mir_drop_order.rs b/src/test/run-pass/mir_drop_order.rs
index 55ac5ca067b..e7da43597f1 100644
--- a/src/test/run-pass/mir_drop_order.rs
+++ b/src/test/run-pass/mir_drop_order.rs
@@ -9,23 +9,27 @@
 // except according to those terms.
 
 use std::cell::RefCell;
+use std::panic;
 
 pub struct DropLogger<'a> {
     id: usize,
-    log: &'a RefCell<Vec<usize>>
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>
 }
 
 impl<'a> Drop for DropLogger<'a> {
     fn drop(&mut self) {
-        self.log.borrow_mut().push(self.id);
+        self.log.0.borrow_mut().push(self.id);
     }
 }
 
+struct InjectedFailure;
+
+#[allow(unreachable_code)]
 fn main() {
-    let log = RefCell::new(vec![]);
+    let log = panic::AssertUnwindSafe(RefCell::new(vec![]));
     let d = |id| DropLogger { id: id, log: &log };
     let get = || -> Vec<_> {
-        let mut m = log.borrow_mut();
+        let mut m = log.0.borrow_mut();
         let n = m.drain(..);
         n.collect()
     };
@@ -39,4 +43,13 @@ fn main() {
     // *after* the let result (tho they have the same scope
     // as far as scope-based borrowck goes).
     assert_eq!(get(), vec![0, 2, 3, 1]);
+
+    let _ = std::panic::catch_unwind(|| {
+        (d(4), &d(5), d(6), &d(7), panic!(InjectedFailure));
+    });
+
+    // here, the temporaries (5/7) live until the end of the
+    // containing statement, which is destroyed after the operands
+    // (4/6) on a panic.
+    assert_eq!(get(), vec![6, 4, 7, 5]);
 }