about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/expr/as_place.rs10
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs65
-rw-r--r--src/test/mir-opt/loop_test.rs1
-rw-r--r--src/test/ui/borrowck/assign-never-type.rs14
4 files changed, 61 insertions, 29 deletions
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 0640c01d255..82accb47437 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -73,13 +73,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
 
                 let slice = unpack!(block = this.as_place(block, lhs));
-                // region_scope=None so place indexes live forever. They are scalars so they
-                // do not need storage annotations, and they are often copied between
-                // places.
                 // Making this a *fresh* temporary also means we do not have to worry about
                 // the index changing later: Nothing will ever change this temporary.
                 // The "retagging" transformation (for Stacked Borrows) relies on this.
-                let idx = unpack!(block = this.as_temp(block, None, index, Mutability::Mut));
+                let idx = unpack!(block = this.as_temp(
+                    block,
+                    expr.temp_lifetime,
+                    index,
+                    Mutability::Not,
+                ));
 
                 // bounds check:
                 let (len, lt) = (
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 1fe6be8bbc8..dbcc330eca3 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -3,6 +3,7 @@
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::build::scope::DropKind;
 use crate::hair::*;
+use rustc::hir;
 use rustc::middle::region;
 use rustc::mir::*;
 
@@ -66,32 +67,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         };
         let temp_place = &Place::from(temp);
 
-        if !expr_ty.is_never() {
-            this.cfg.push(
-                block,
-                Statement {
-                    source_info,
-                    kind: StatementKind::StorageLive(temp),
-                },
-            );
-
-            // In constants, `temp_lifetime` is `None` for temporaries that live for the
-            // `'static` lifetime. Thus we do not drop these temporaries and simply leak them.
-            // This is equivalent to what `let x = &foo();` does in functions. The temporary
-            // is lifted to their surrounding scope. In a function that means the temporary lives
-            // until just before the function returns. In constants that means it outlives the
-            // constant's initialization value computation. Anything outliving a constant
-            // must have the `'static` lifetime and live forever.
-            // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything
-            // within a block will keep the regular drops just like runtime code.
-            if let Some(temp_lifetime) = temp_lifetime {
-                this.schedule_drop(
-                    expr_span,
-                    temp_lifetime,
-                    temp,
-                    expr_ty,
-                    DropKind::Storage,
+        match expr.kind {
+            // Don't bother with StorageLive and Dead for these temporaries,
+            // they are never assigned.
+            ExprKind::Break { .. } |
+            ExprKind::Continue { .. } |
+            ExprKind::Return { .. } => (),
+            ExprKind::Block {
+                body: hir::Block { expr: None, targeted_by_break: false, .. }
+            } if expr_ty.is_never() => (),
+            _ => {
+                this.cfg.push(
+                    block,
+                    Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(temp),
+                    },
                 );
+
+                // In constants, `temp_lifetime` is `None` for temporaries that
+                // live for the `'static` lifetime. Thus we do not drop these
+                // temporaries and simply leak them.
+                // This is equivalent to what `let x = &foo();` does in
+                // functions. The temporary is lifted to their surrounding
+                // scope. In a function that means the temporary lives until
+                // just before the function returns. In constants that means it
+                // outlives the constant's initialization value computation.
+                // Anything outliving a constant must have the `'static`
+                // lifetime and live forever.
+                // Anything with a shorter lifetime (e.g the `&foo()` in
+                // `bar(&foo())` or anything within a block will keep the
+                // regular drops just like runtime code.
+                if let Some(temp_lifetime) = temp_lifetime {
+                    this.schedule_drop(
+                        expr_span,
+                        temp_lifetime,
+                        temp,
+                        expr_ty,
+                        DropKind::Storage,
+                    );
+                }
             }
         }
 
diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs
index 177080c04f9..418febbdc01 100644
--- a/src/test/mir-opt/loop_test.rs
+++ b/src/test/mir-opt/loop_test.rs
@@ -26,6 +26,7 @@ fn main() {
 //        _1 = ();
 //        StorageDead(_2);
 //        StorageDead(_1);
+//        StorageLive(_4);
 //        goto -> bb5;
 //    }
 //    ...
diff --git a/src/test/ui/borrowck/assign-never-type.rs b/src/test/ui/borrowck/assign-never-type.rs
new file mode 100644
index 00000000000..4f30ea14670
--- /dev/null
+++ b/src/test/ui/borrowck/assign-never-type.rs
@@ -0,0 +1,14 @@
+// Regression test for issue 62165
+
+// check-pass
+
+#![feature(never_type)]
+
+pub fn main() {
+    loop {
+        match None {
+            None => return,
+            Some(val) => val,
+        };
+    };
+}