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`).