]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/build/expr/as_temp.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_mir / build / expr / as_temp.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! See docs in build/expr/mod.rs
12
13 use build::{BlockAnd, BlockAndExtension, Builder};
14 use build::expr::category::Category;
15 use hair::*;
16 use rustc::mir::repr::*;
17
18 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
19 /// Compile `expr` into a fresh temporary. This is used when building
20 /// up rvalues so as to freeze the value that will be consumed.
21 pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>>
22 where M: Mirror<'tcx, Output = Expr<'tcx>>
23 {
24 let expr = self.hir.mirror(expr);
25 self.expr_as_temp(block, expr)
26 }
27
28 fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<Lvalue<'tcx>> {
29 debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
30 let this = self;
31
32 if let ExprKind::Scope { extent, value } = expr.kind {
33 return this.in_scope(extent, block, |this| this.as_temp(block, value));
34 }
35
36 let expr_ty = expr.ty.clone();
37 let temp = this.temp(expr_ty.clone());
38 let temp_lifetime = expr.temp_lifetime;
39 let expr_span = expr.span;
40 let source_info = this.source_info(expr_span);
41
42 if temp_lifetime.is_some() {
43 this.cfg.push(block, Statement {
44 source_info: source_info,
45 kind: StatementKind::StorageLive(temp.clone())
46 });
47 }
48
49 // Careful here not to cause an infinite cycle. If we always
50 // called `into`, then for lvalues like `x.f`, it would
51 // eventually fallback to us, and we'd loop. There's a reason
52 // for this: `as_temp` is the point where we bridge the "by
53 // reference" semantics of `as_lvalue` with the "by value"
54 // semantics of `into`, `as_operand`, `as_rvalue`, and (of
55 // course) `as_temp`.
56 match Category::of(&expr.kind).unwrap() {
57 Category::Lvalue => {
58 let lvalue = unpack!(block = this.as_lvalue(block, expr));
59 let rvalue = Rvalue::Use(Operand::Consume(lvalue));
60 this.cfg.push_assign(block, source_info, &temp, rvalue);
61 }
62 _ => {
63 unpack!(block = this.into(&temp, block, expr));
64 }
65 }
66
67 // In constants, temp_lifetime is None. We should not need to drop
68 // anything because no values with a destructor can be created in
69 // a constant at this time, even if the type may need dropping.
70 if let Some(temp_lifetime) = temp_lifetime {
71 this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty);
72 }
73
74 block.and(temp)
75 }
76 }