Generate a direct assignment in MIR for let x = y;

This commit is contained in:
Matthew Jasper 2018-06-27 22:04:45 +01:00
parent 4aff10bb1b
commit 9185bb3061
3 changed files with 34 additions and 26 deletions

View File

@ -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

View File

@ -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,

View File

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