]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
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 | ||
92a42be0 | 13 | use build::{BlockAnd, BlockAndExtension, Builder}; |
e9174d1e SL |
14 | use build::expr::category::Category; |
15 | use hair::*; | |
92a42be0 | 16 | use rustc::mir::repr::*; |
e9174d1e | 17 | |
b039eaaf | 18 | impl<'a,'tcx> Builder<'a,'tcx> { |
e9174d1e SL |
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. | |
b039eaaf SL |
21 | pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>> |
22 | where M: Mirror<'tcx, Output = Expr<'tcx>> | |
e9174d1e SL |
23 | { |
24 | let expr = self.hir.mirror(expr); | |
25 | self.expr_as_temp(block, expr) | |
26 | } | |
27 | ||
b039eaaf SL |
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); | |
e9174d1e SL |
30 | let this = self; |
31 | ||
b039eaaf | 32 | if let ExprKind::Scope { extent, value } = expr.kind { |
54a0048b | 33 | return this.in_scope(extent, block, |this, _| this.as_temp(block, value)); |
e9174d1e SL |
34 | } |
35 | ||
36 | let expr_ty = expr.ty.clone(); | |
37 | let temp = this.temp(expr_ty.clone()); | |
38 | let temp_lifetime = match expr.temp_lifetime { | |
39 | Some(t) => t, | |
40 | None => { | |
54a0048b | 41 | span_bug!(expr.span, "no temp_lifetime for expr"); |
e9174d1e SL |
42 | } |
43 | }; | |
7453a54e | 44 | this.schedule_drop(expr.span, temp_lifetime, &temp, expr_ty); |
e9174d1e SL |
45 | |
46 | // Careful here not to cause an infinite cycle. If we always | |
47 | // called `into`, then for lvalues like `x.f`, it would | |
48 | // eventually fallback to us, and we'd loop. There's a reason | |
49 | // for this: `as_temp` is the point where we bridge the "by | |
50 | // reference" semantics of `as_lvalue` with the "by value" | |
51 | // semantics of `into`, `as_operand`, `as_rvalue`, and (of | |
52 | // course) `as_temp`. | |
53 | match Category::of(&expr.kind).unwrap() { | |
54 | Category::Lvalue => { | |
55 | let expr_span = expr.span; | |
56 | let lvalue = unpack!(block = this.as_lvalue(block, expr)); | |
57 | let rvalue = Rvalue::Use(Operand::Consume(lvalue)); | |
54a0048b SL |
58 | let scope_id = this.innermost_scope_id(); |
59 | this.cfg.push_assign(block, scope_id, expr_span, &temp, rvalue); | |
e9174d1e SL |
60 | } |
61 | _ => { | |
62 | unpack!(block = this.into(&temp, block, expr)); | |
63 | } | |
64 | } | |
65 | ||
66 | block.and(temp) | |
67 | } | |
68 | } |