about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs19
-rw-r--r--src/librustc_mir/build/expr/into.rs39
-rw-r--r--src/librustc_mir/build/expr/mod.rs2
3 files changed, 34 insertions, 26 deletions
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 1fc608c52c6..d905b383316 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -11,7 +11,6 @@
 //! See docs in build/expr/mod.rs
 
 use build::{BlockAnd, BlockAndExtension, Builder};
-use build::expr::category::Category;
 use hair::*;
 use rustc::middle::region;
 use rustc::mir::*;
@@ -57,23 +56,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             });
         }
 
-        // Careful here not to cause an infinite cycle. If we always
-        // called `into`, then for places like `x.f`, it would
-        // eventually fallback to us, and we'd loop. There's a reason
-        // for this: `as_temp` is the point where we bridge the "by
-        // reference" semantics of `as_place` with the "by value"
-        // semantics of `into`, `as_operand`, `as_rvalue`, and (of
-        // course) `as_temp`.
-        match Category::of(&expr.kind).unwrap() {
-            Category::Place => {
-                let place = unpack!(block = this.as_place(block, expr));
-                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
-                this.cfg.push_assign(block, source_info, &Place::Local(temp), rvalue);
-            }
-            _ => {
-                unpack!(block = this.into(&Place::Local(temp), block, expr));
-            }
-        }
+        unpack!(block = this.into(&Place::Local(temp), block, expr));
 
         // In constants, temp_lifetime is None. We should not need to drop
         // anything because no values with a destructor can be created in
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 94b387abe3c..59a7f49af80 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -288,6 +288,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block.unit()
             }
 
+            // Avoid creating a temporary
+            ExprKind::VarRef { .. } |
+            ExprKind::SelfRef |
+            ExprKind::StaticRef { .. } => {
+                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
+
+                let place = unpack!(block = this.as_place(block, expr));
+                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
+                this.cfg.push_assign(block, source_info, destination, rvalue);
+                block.unit()
+            }
+            ExprKind::Index { .. } |
+            ExprKind::Deref { .. } |
+            ExprKind::Field { .. } => {
+                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
+
+                // Create a "fake" temporary variable so that we check that the
+                // value is Sized. Usually, this is caught in type checking, but
+                // in the case of box expr there is no such check.
+                if let Place::Projection(..) = destination {
+                    this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span));
+                }
+
+                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
+
+                let place = unpack!(block = this.as_place(block, expr));
+                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
+                this.cfg.push_assign(block, source_info, destination, rvalue);
+                block.unit()
+            }
+
             // these are the cases that are more naturally handled by some other mode
             ExprKind::Unary { .. } |
             ExprKind::Binary { .. } |
@@ -300,18 +331,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Unsize { .. } |
             ExprKind::Repeat { .. } |
             ExprKind::Borrow { .. } |
-            ExprKind::VarRef { .. } |
-            ExprKind::SelfRef |
-            ExprKind::StaticRef { .. } |
             ExprKind::Array { .. } |
             ExprKind::Tuple { .. } |
             ExprKind::Adt { .. } |
             ExprKind::Closure { .. } |
-            ExprKind::Index { .. } |
-            ExprKind::Deref { .. } |
             ExprKind::Literal { .. } |
-            ExprKind::Yield { .. } |
-            ExprKind::Field { .. } => {
+            ExprKind::Yield { .. } => {
                 debug_assert!(match Category::of(&expr.kind).unwrap() {
                     Category::Rvalue(RvalueFunc::Into) => false,
                     _ => true,
diff --git a/src/librustc_mir/build/expr/mod.rs b/src/librustc_mir/build/expr/mod.rs
index 0fd4b8e7e23..a63cf41f066 100644
--- a/src/librustc_mir/build/expr/mod.rs
+++ b/src/librustc_mir/build/expr/mod.rs
@@ -65,7 +65,7 @@
 //! which can fallback to `into`. So if one of the `ExprKind` variants is not, in fact,
 //! implemented in the category where it is supposed to be, there will be a problem.
 //!
-//! Of those fallbacks, the most interesting one is `as_temp`, because
+//! Of those fallbacks, the most interesting one is `into`, because
 //! it discriminates based on the category of the expression. This is
 //! basically the point where the "by value" operations are bridged
 //! over to the "by reference" mode (`as_place`).