]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/expr/as_temp.rs
a334923546fb2df76a8c4ccb73cd242bf11ae6ab
[rust.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::middle::region::CodeExtent;
17 use rustc::mir::*;
18
19 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
20     /// Compile `expr` into a fresh temporary. This is used when building
21     /// up rvalues so as to freeze the value that will be consumed.
22     pub fn as_temp<M>(&mut self,
23                       block: BasicBlock,
24                       temp_lifetime: Option<CodeExtent>,
25                       expr: M)
26                       -> BlockAnd<Lvalue<'tcx>>
27         where M: Mirror<'tcx, Output = Expr<'tcx>>
28     {
29         let expr = self.hir.mirror(expr);
30         self.expr_as_temp(block, temp_lifetime, expr)
31     }
32
33     fn expr_as_temp(&mut self,
34                     mut block: BasicBlock,
35                     temp_lifetime: Option<CodeExtent>,
36                     expr: Expr<'tcx>)
37                     -> BlockAnd<Lvalue<'tcx>> {
38         debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
39         let this = self;
40
41         if let ExprKind::Scope { extent, value } = expr.kind {
42             return this.in_scope(extent, block, |this| {
43                 this.as_temp(block, temp_lifetime, value)
44             });
45         }
46
47         let expr_ty = expr.ty.clone();
48         let expr_span = expr.span;
49         let temp = this.temp(expr_ty.clone(), expr_span);
50         let source_info = this.source_info(expr_span);
51
52         if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
53             this.hir.tcx().sess.span_warn(
54                 expr_span,
55                 "this temporary used to live longer - see issue #39283 \
56 (https://github.com/rust-lang/rust/issues/39283)");
57         }
58
59         if !expr_ty.is_never() && temp_lifetime.is_some() {
60             this.cfg.push(block, Statement {
61                 source_info: source_info,
62                 kind: StatementKind::StorageLive(temp.clone())
63             });
64         }
65
66         // Careful here not to cause an infinite cycle. If we always
67         // called `into`, then for lvalues like `x.f`, it would
68         // eventually fallback to us, and we'd loop. There's a reason
69         // for this: `as_temp` is the point where we bridge the "by
70         // reference" semantics of `as_lvalue` with the "by value"
71         // semantics of `into`, `as_operand`, `as_rvalue`, and (of
72         // course) `as_temp`.
73         match Category::of(&expr.kind).unwrap() {
74             Category::Lvalue => {
75                 let lvalue = unpack!(block = this.as_lvalue(block, expr));
76                 let rvalue = Rvalue::Use(Operand::Consume(lvalue));
77                 this.cfg.push_assign(block, source_info, &temp, rvalue);
78             }
79             _ => {
80                 unpack!(block = this.into(&temp, block, expr));
81             }
82         }
83
84         // In constants, temp_lifetime is None. We should not need to drop
85         // anything because no values with a destructor can be created in
86         // a constant at this time, even if the type may need dropping.
87         if let Some(temp_lifetime) = temp_lifetime {
88             this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty);
89         }
90
91         block.and(temp)
92     }
93 }